Major system rework

This commit is contained in:
RatzzFatzz
2025-12-10 21:31:29 +01:00
parent d5e452557c
commit 0b61deccbf
44 changed files with 865 additions and 851 deletions

View File

@@ -26,31 +26,44 @@ Attribute-config must be entered in pairs: `audio:subtitle`; Example: `jpn:eng`.
### Available parameters ### Available parameters
``` ```
-a, --attribute-config=<attributeConfig>... * -a, --attribute-config=<attributeConfig>...
List of audio:subtitle pairs used to match in order and update files accordingly (e.g. jpn:eng jpn:ger) List of audio:subtitle pairs used to match in order
-c, --coherent=<coherent> try to match all files in dir of depth with the same attribute config and update files accordingly (e.g. jpn:eng jpn:
-cf, --force-coherent changes are only applied if it's a coherent match ger)
--commentary-keywords=<commentaryKeywords>[, <commentaryKeywords>...]... * -l, --library=<libraryPath>
Keywords to identify commentary tracks (Defaults will be overwritten; Default: commentary, director)
-d, --filter-date=<filterDate>
only consider files created newer than entered date (format: "dd.MM.yyyy-HH:mm:ss")
--debug Enable debug logging
-e, --excluded-directory=<excludedDirectories>...
Directories to be excluded, combines with config file
--forced-keywords=<forcedKeywords>[, <forcedKeywords>...]...
Keywords to identify forced tracks (Defaults will be overwritten; Default: forced, signs, songs)
-h, --help Show this help message and exit.
-i, --include-pattern=<includePattern>
include files matching pattern (default: ".*")
-l, --library=<libraryPath>
path to library path to library
-m, --mkvtoolnix=<mkvToolNix> -m, --mkvtoolnix=<mkvToolNix>
path to mkvtoolnix installation path to mkvtoolnix installation
-n, --only-new-file sets filter-date to last successful execution (overwrites input of filter-date)
--preferred-subtitles=<preferredSubtitles>[, <preferredSubtitles>...]...
Keywords to prefer specific subtitle tracks (Defaults will be overwritten; Default: unstyled)
-s, --safemode test run (no files will be changes) -s, --safemode test run (no files will be changes)
-t, --threads=<threads> thread count (default: 2) -t, --threads=<threads> thread count (default: 2)
-c, --coherent=<coherent> try to match all files in dir of depth with the
same attribute config
-cf, --force-coherent changes are only applied if it's a coherent match
-n, --only-new-file sets filter-date to last successful execution
(overwrites input of filter-date)
-d, --filter-date=<filterDate>
only consider files created newer than entered date
(format: "dd.MM.yyyy-HH:mm:ss")
-i, --include-pattern=<includePattern>
include files matching pattern (default: ".*")
-e, --excluded=<excluded>...
Directories and files to be excluded (no wildcard)
-o, -overwrite-forced remove all forced flags
--forced-keywords=<forcedKeywords>[, <forcedKeywords>...]...
Keywords to identify forced tracks (Defaults will
be overwritten; Default: forced, signs, songs)
--commentary-keywords=<commentaryKeywords>[, <commentaryKeywords>...]...
Keywords to identify commentary tracks (Defaults
will be overwritten; Default: comment,
commentary, director)
--hearing-impaired=<hearingImpaired>[, <hearingImpaired>...]...
Keywords to identify hearing impaired tracks
(Defaults will be overwritten; Default: SDH
--preferred-subtitles=<preferredSubtitles>[, <preferredSubtitles>...]...
Keywords to prefer specific subtitle tracks
(Defaults will be overwritten; Default: unstyled)
--debug Enable debug logging
-h, --help Show this help message and exit.
-V, --version Print version information and exit. -V, --version Print version information and exit.
``` ```
If you need more information how each parameter works, check out [this wiki page](https://github.com/RatzzFatzz/MKVAudioSubtitleChanger/wiki/Parameters-v4). If you need more information how each parameter works, check out [this wiki page](https://github.com/RatzzFatzz/MKVAudioSubtitleChanger/wiki/Parameters-v4).

View File

@@ -1,12 +1,11 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger; package at.pcgamingfreaks.mkvaudiosubtitlechanger;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.InputConfig; import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.InputConfig;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validation.ValidationExecutionStrategy; import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.validation.ValidationExecutionStrategy;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.CachedMkvFileProcessor; import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.processors.CachedMkvFileProcessor;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.kernel.AttributeUpdaterKernel; import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.kernel.AttributeUpdaterKernel;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.kernel.CoherentAttributeUpdaterKernel; import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.kernel.CoherentAttributeUpdaterKernel;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.kernel.DefaultAttributeUpdaterKernel; import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.kernel.DefaultAttributeUpdaterKernel;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.MkvFileCollector;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.util.ProjectUtil; import at.pcgamingfreaks.mkvaudiosubtitlechanger.util.ProjectUtil;
import lombok.Getter; import lombok.Getter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@@ -53,8 +52,8 @@ public class Main implements Runnable {
InputConfig.setInstance(config); InputConfig.setInstance(config);
AttributeUpdaterKernel kernel = InputConfig.getInstance().getCoherent() != null AttributeUpdaterKernel kernel = InputConfig.getInstance().getCoherent() != null
? new CoherentAttributeUpdaterKernel(new MkvFileCollector(), new CachedMkvFileProcessor()) ? new CoherentAttributeUpdaterKernel(new CachedMkvFileProcessor())
: new DefaultAttributeUpdaterKernel(new MkvFileCollector(), new CachedMkvFileProcessor()); : new DefaultAttributeUpdaterKernel(new CachedMkvFileProcessor());
kernel.execute(); kernel.execute();
} }
} }

View File

@@ -1,15 +0,0 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.FileAttribute;
import java.io.File;
import java.util.List;
public class CachedMkvFileProcessor extends MkvFileProcessor {
Cache<File, List<FileAttribute>> cache = new Cache<>();
@Override
public List<FileAttribute> loadAttributes(File file) {
return cache.retrieve(file, super::loadAttributes);
}
}

View File

@@ -1,22 +0,0 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl;
import java.io.File;
import java.util.List;
public interface FileCollector {
/**
* @param path leads to one file directly or a directory which will be loaded recursively
* @return list of all files within the directory
*/
List<File> loadFiles(String path);
/**
* Load all directories from path, but only until depth is reached.
*
* @param path leads to a directory which will be loaded recursively until depth
* @param depth limit directory crawling
* @return list of directory until depth
*/
List<File> loadDirectories(String path, int depth);
}

View File

@@ -1,33 +1,45 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl; package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.InputConfig; 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 at.pcgamingfreaks.mkvaudiosubtitlechanger.util.DateUtils;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import java.io.File; 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.util.Date;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Slf4j @Slf4j
public class FileFilter { public class FileFilter {
static boolean accept(File pathName, String[] fileExtensions) { private static final String EXTENSION_GROUP = "extension";
if (hasProperFileExtension(pathName, fileExtensions) private static final Pattern extensionPattern = Pattern.compile(String.format(".*(?<%s>\\..*)", EXTENSION_GROUP));
&& hasMatchingPattern(pathName)
&& isNewer(pathName)) { public static boolean accept(File pathName, Set<String> fileExtensions) {
return true; // Ignore files irrelevant for statistics
if (!hasProperFileExtension(pathName, new HashSet<>(fileExtensions))) {
return false;
} }
ResultStatistic.getInstance().total(); ResultStatistic.getInstance().total();
ResultStatistic.getInstance().excluded(); if (!hasMatchingPattern(pathName)
return false; || !isNewer(pathName)
|| isExcluded(pathName, new HashSet<>(InputConfig.getInstance().getExcluded()))) {
ResultStatistic.getInstance().excluded();
return false;
}
return true;
} }
private static boolean hasProperFileExtension(File pathName, String[] fileExtensions) { private static boolean hasProperFileExtension(File pathName, Set<String> fileExtensions) {
return StringUtils.endsWithAny(pathName.getAbsolutePath().toLowerCase(), fileExtensions); Matcher matcher = extensionPattern.matcher(pathName.getName());
return matcher.find() && fileExtensions.contains(matcher.group(EXTENSION_GROUP));
} }
private static boolean hasMatchingPattern(File pathName) { private static boolean hasMatchingPattern(File pathName) {
@@ -49,4 +61,15 @@ public class FileFilter {
private static boolean isNewer(Date creationDate) { private static boolean isNewer(Date creationDate) {
return creationDate.toInstant().isAfter(InputConfig.getInstance().getFilterDate().toInstant()); return creationDate.toInstant().isAfter(InputConfig.getInstance().getFilterDate().toInstant());
} }
private static boolean isExcluded(File pathName, Set<String> excludedDirs) {
if (excludedDirs.contains(pathName.getPath())) return true;
// TODO improve partial matches and wildcard?
for (String excludedDir : excludedDirs) {
if (pathName.getPath().startsWith(excludedDir)) return true;
}
return false;
}
} }

View File

@@ -1,51 +0,0 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.exceptions.MkvToolNixException;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.AttributeConfig;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.FileAttribute;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.FileInfo;
import java.io.File;
import java.io.IOException;
import java.util.List;
public interface FileProcessor {
/**
* Load track information from file.
*
* @param file Takes the file from which the attributes will be returned
* @return list of all important attributes
*/
List<FileAttribute> loadAttributes(File file);
/**
* Populate FileInfoDto with the currently set default tracks.
* @param info to be populated
* @param attributes Track information of FileInfoDto
* @param nonForcedTracks List of all not forced tracks
*/
void detectDefaultTracks(FileInfo info, List<FileAttribute> attributes, List<FileAttribute> nonForcedTracks);
/**
* Populate FileInfoDto with the desired tracks, based on AttributeConfig.
* @param info to be populated
* @param nonForcedTracks List of all non-forced tracks
* @param nonCommentaryTracks List of all non-commentary tracks
*/
void detectDesiredTracks(FileInfo info, List<FileAttribute> nonForcedTracks, List<FileAttribute> nonCommentaryTracks,
AttributeConfig... configs);
List<FileAttribute> retrieveNonForcedTracks(List<FileAttribute> attributes);
List<FileAttribute> retrieveNonCommentaryTracks(List<FileAttribute> attributes);
/**
* Update the file.
* @param file to be updated
* @param fileInfo information used to update file
* @throws IOException when error occurs accessing file retrieving information
* @throws MkvToolNixException when error occurs while sending query to mkvpropedit
*/
void update(File file, FileInfo fileInfo) throws IOException, MkvToolNixException;
}

View File

@@ -1,49 +0,0 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl;
import lombok.extern.slf4j.Slf4j;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@Slf4j
public class MkvFileCollector implements FileCollector {
private static final String[] fileExtensions = new String[]{".mkv", ".mka", ".mks", ".mk3d"};
/**
* {@inheritDoc}
*/
@Override
public List<File> loadFiles(String path) {
try (Stream<Path> paths = Files.walk(Paths.get(path))) {
return paths.filter(Files::isRegularFile)
.map(Path::toFile)
.filter(file -> FileFilter.accept(file, fileExtensions))
.collect(Collectors.toList());
} catch (IOException e) {
log.error("Couldn't find file or directory!", e);
return new ArrayList<>();
}
}
/**
* {@inheritDoc}
*/
@Override
public List<File> loadDirectories(String path, int depth) {
try (Stream<Path> paths = Files.walk(Paths.get(path), depth)) {
return paths.map(Path::toFile)
.filter(File::isDirectory)
.collect(Collectors.toList());
} catch (IOException e) {
log.error("Couldn't find file or directory!", e);
return new ArrayList<>();
}
}
}

View File

@@ -1,198 +0,0 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.InputConfig;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.exceptions.MkvToolNixException;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.*;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.util.SetUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.core.util.IOUtils;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.LaneType.AUDIO;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.LaneType.SUBTITLES;
import static java.lang.String.format;
@Slf4j
public class MkvFileProcessor implements FileProcessor {
private final ObjectMapper mapper = new ObjectMapper();
private static final SubtitleTrackComparator subtitleTrackComparator =
new SubtitleTrackComparator(InputConfig.getInstance().getPreferredSubtitles().toArray(new String[0]));
private static final String DISABLE_DEFAULT_TRACK = "--edit track:%s --set flag-default=0";
private static final String ENABLE_DEFAULT_TRACK = "--edit track:%s --set flag-default=1";
private static final String DISABLE_FORCED_TRACK = "--edit track:%s --set flag-forced=0";
private static final String ENABLE_FORCED_TRACK = "--edit track:%s --set flag-forced=1";
@SuppressWarnings("unchecked")
@Override
public List<FileAttribute> loadAttributes(File file) {
Map<String, Object> jsonMap;
List<FileAttribute> fileAttributes = new ArrayList<>();
try {
String[] command = new String[]{
InputConfig.getInstance().getPathFor(MkvToolNix.MKV_MERGE),
"--identify",
"--identification-format",
"json",
file.getAbsolutePath()
};
log.debug("Executing '{}': {}", file.getAbsolutePath(), String.join(" ", command));
InputStream inputStream = Runtime.getRuntime().exec(command)
.getInputStream();
jsonMap = mapper.readValue(inputStream, Map.class);
List<Map<String, Object>> tracks = (List<Map<String, Object>>) jsonMap.get("tracks");
if (tracks == null) {
log.warn("Couldn't retrieve information of {}", file.getAbsolutePath());
return new ArrayList<>();
}
for (Map<String, Object> attribute : tracks) {
if (!"video".equals(attribute.get("type"))) {
Map<String, Object> properties = (Map<String, Object>) attribute.get("properties");
fileAttributes.add(new FileAttribute(
(int) properties.get("number"),
(String) properties.get("language"),
(String) properties.get("track_name"),
(Boolean) properties.getOrDefault("default_track", false),
(Boolean) properties.getOrDefault("forced_track", false),
LaneType.valueOf(((String) attribute.get("type")).toUpperCase(Locale.ENGLISH))));
}
}
log.debug("File attributes of '{}': {}", file.getAbsolutePath(), fileAttributes.toString());
} catch (IOException e) {
log.error("File could not be found or loaded: ", e);
System.out.println("File could not be found or loaded: " + file.getAbsolutePath());
}
return fileAttributes;
}
/**
* {@inheritDoc}
*/
@Override
public void detectDefaultTracks(FileInfo info, List<FileAttribute> attributes, List<FileAttribute> nonForcedTracks) {
for (FileAttribute attribute : attributes) {
if (AUDIO.equals(attribute.type())) {
if (attribute.defaultTrack()) info.getExistingDefaultAudioLanes().add(attribute);
if (attribute.forcedTrack()) info.getExistingForcedAudioLanes().add(attribute);
} else if (SUBTITLES.equals(attribute.type())) {
if (attribute.defaultTrack()) info.getExistingDefaultSubtitleLanes().add(attribute);
if (attribute.forcedTrack()) info.getExistingForcedSubtitleLanes().add(attribute);
else if (!nonForcedTracks.contains(attribute)) info.getDesiredForcedSubtitleLanes().add(attribute);
}
}
}
/**
* {@inheritDoc}
*/
@Override
public void detectDesiredTracks(FileInfo info, List<FileAttribute> nonForcedTracks, List<FileAttribute> nonCommentaryTracks,
AttributeConfig... configs) {
Set<FileAttribute> tracks = SetUtils.retainOf(nonForcedTracks, nonCommentaryTracks);
Set<FileAttribute> audioTracks = tracks.stream().filter(a -> AUDIO.equals(a.type())).collect(Collectors.toSet());
Set<FileAttribute> subtitleTracks = tracks.stream().filter(a -> SUBTITLES.equals(a.type())).collect(Collectors.toSet());
for (AttributeConfig config : configs) {
Optional<FileAttribute> desiredAudio = detectDesiredTrack(config.getAudioLanguage(), audioTracks).findFirst();
Optional<FileAttribute> desiredSubtitle = detectDesiredSubtitleTrack(config.getSubtitleLanguage(), subtitleTracks).findFirst();
if (("OFF".equals(config.getAudioLanguage()) || desiredAudio.isPresent())
&& ("OFF".equals(config.getSubtitleLanguage()) || desiredSubtitle.isPresent())) {
info.setMatchedConfig(config);
info.setDesiredDefaultAudioLane(desiredAudio.orElse(null));
info.setDesiredDefaultSubtitleLane(desiredSubtitle.orElse(null));
break;
}
}
}
private Stream<FileAttribute> detectDesiredTrack(String language, Set<FileAttribute> tracks) {
return tracks.stream().filter(track -> language.equals(track.language()));
}
private Stream<FileAttribute> detectDesiredSubtitleTrack(String language, Set<FileAttribute> tracks) {
return detectDesiredTrack(language, tracks)
.sorted(subtitleTrackComparator.reversed());
}
@Override
public List<FileAttribute> retrieveNonForcedTracks(List<FileAttribute> attributes) {
return attributes.stream()
.filter(elem -> !StringUtils.containsAnyIgnoreCase(elem.trackName(),
InputConfig.getInstance().getForcedKeywords().toArray(new CharSequence[0])))
.filter(elem -> !elem.forcedTrack())
.collect(Collectors.toList());
}
@Override
public List<FileAttribute> retrieveNonCommentaryTracks(List<FileAttribute> attributes) {
return attributes.stream()
.filter(elem -> !StringUtils.containsAnyIgnoreCase(elem.trackName(),
InputConfig.getInstance().getCommentaryKeywords().toArray(new CharSequence[0])))
.collect(Collectors.toList());
}
/**
* {@inheritDoc}
*/
@Override
public void update(File file, FileInfo fileInfo) throws IOException, MkvToolNixException {
List<String> command = new ArrayList<>();
command.add(InputConfig.getInstance().getPathFor(MkvToolNix.MKV_PROP_EDIT));
command.add(String.format(file.getAbsolutePath()));
if (fileInfo.isAudioDifferent()) {
removeExistingAndAddDesiredLanes(fileInfo.getExistingDefaultAudioLanes(), fileInfo.getDesiredDefaultAudioLane(), command);
}
if (!fileInfo.getExistingForcedAudioLanes().isEmpty()) {
for (FileAttribute track : fileInfo.getExistingForcedAudioLanes()) {
command.addAll(format(DISABLE_FORCED_TRACK, track.id()));
}
}
if (fileInfo.isSubtitleDifferent()) {
removeExistingAndAddDesiredLanes(fileInfo.getExistingDefaultSubtitleLanes(), fileInfo.getDesiredDefaultSubtitleLane(), command);
}
if (fileInfo.areForcedTracksDifferent()) {
for (FileAttribute track : fileInfo.getDesiredForcedSubtitleLanes()) {
command.addAll(format(ENABLE_FORCED_TRACK, track.id()));
}
}
log.debug("Executing '{}'", String.join(" ", command));
InputStream inputstream = Runtime.getRuntime().exec(command.toArray(new String[0])).getInputStream();
String output = IOUtils.toString(new InputStreamReader(inputstream));
log.debug("Result: {}", output);
if (output.contains("Error")) throw new MkvToolNixException(output);
}
private void removeExistingAndAddDesiredLanes(Set<FileAttribute> existingDefaultLanes, FileAttribute desiredDefaultLanes, List<String> command) {
if (existingDefaultLanes != null && !existingDefaultLanes.isEmpty()) {
for (FileAttribute track : existingDefaultLanes) {
command.addAll(format(DISABLE_DEFAULT_TRACK, track.id()));
}
}
if (desiredDefaultLanes != null) {
command.addAll(format(ENABLE_DEFAULT_TRACK, desiredDefaultLanes.id()));
}
}
private List<String> format(String format, Object... args) {
return Arrays.asList(String.format(format, args).split(" "));
}
}

View File

@@ -1,20 +1,20 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl; package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.FileAttribute; import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.TrackAttributes;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.util.Comparator; import java.util.Comparator;
@RequiredArgsConstructor @RequiredArgsConstructor
public class SubtitleTrackComparator implements Comparator<FileAttribute> { public class SubtitleTrackComparator implements Comparator<TrackAttributes> {
private final String[] preferredSubtitles; private final String[] preferredSubtitles;
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
@Override @Override
public int compare(FileAttribute track1, FileAttribute track2) { public int compare(TrackAttributes track1, TrackAttributes track2) {
int result = 0; int result = 0;
if (StringUtils.containsAnyIgnoreCase(track1.trackName(), preferredSubtitles)) { if (StringUtils.containsAnyIgnoreCase(track1.trackName(), preferredSubtitles)) {
@@ -25,8 +25,8 @@ public class SubtitleTrackComparator implements Comparator<FileAttribute> {
} }
if (result == 0) { if (result == 0) {
if (track1.defaultTrack()) result++; if (track1.defaultt()) result++;
if (track2.defaultTrack()) result--; if (track2.defaultt()) result--;
} }
return result; return result;

View File

@@ -1,4 +1,4 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.converter; package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.converter;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.AttributeConfig; import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.AttributeConfig;
import picocli.CommandLine; import picocli.CommandLine;
@@ -26,7 +26,7 @@ public class AttributeConfigConverter implements CommandLine.ITypeConverter<Attr
if (!matcher.find()) throw new CommandLine.TypeConversionException("Invalid Attribute config: " + s); if (!matcher.find()) throw new CommandLine.TypeConversionException("Invalid Attribute config: " + s);
return validateResult(new AttributeConfig(matcher.group("audio"), matcher.group("sub"))); return validateResult(new AttributeConfig(matcher.group(AUDIO_GROUP), matcher.group(SUB_GROUP)));
} }
/** /**

View File

@@ -1,13 +1,9 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.kernel; package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.kernel;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.InputConfig;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.exceptions.MkvToolNixException; import at.pcgamingfreaks.mkvaudiosubtitlechanger.exceptions.MkvToolNixException;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.FileCollector; import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.processors.AttributeProcessor;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.FileProcessor; import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.processors.FileProcessor;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.AttributeConfig; import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.*;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.FileAttribute;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.FileInfo;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ResultStatistic;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.util.DateUtils; import at.pcgamingfreaks.mkvaudiosubtitlechanger.util.DateUtils;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.util.ProjectUtil; import at.pcgamingfreaks.mkvaudiosubtitlechanger.util.ProjectUtil;
import at.pcgamingfreaks.yaml.YAML; import at.pcgamingfreaks.yaml.YAML;
@@ -23,19 +19,16 @@ import net.harawata.appdirs.AppDirsFactory;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Collection;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@Slf4j @Slf4j
@RequiredArgsConstructor @RequiredArgsConstructor
public abstract class AttributeUpdaterKernel { public abstract class AttributeUpdaterKernel {
protected final FileCollector collector;
protected final FileProcessor processor; protected final FileProcessor processor;
protected final ResultStatistic statistic = ResultStatistic.getInstance(); protected final ResultStatistic statistic = ResultStatistic.getInstance();
private final ExecutorService executor = Executors.newFixedThreadPool(InputConfig.getInstance().getThreads()); private final ExecutorService executor = Executors.newFixedThreadPool(InputConfig.getInstance().getThreads());
@@ -52,8 +45,10 @@ public abstract class AttributeUpdaterKernel {
statistic.startTimer(); statistic.startTimer();
try (ProgressBar progressBar = pbBuilder().build()) { try (ProgressBar progressBar = pbBuilder().build()) {
List<File> files = loadFiles(InputConfig.getInstance().getLibraryPath().getAbsolutePath()); List<File> files = processor.loadFiles(InputConfig.getInstance().getLibraryPath().getAbsolutePath());
progressBar.maxHint(files.size()); progressBar.maxHint(files.size());
progressBar.refresh();
files.forEach(file -> executor.submit(() -> { files.forEach(file -> executor.submit(() -> {
process(file); process(file);
@@ -64,31 +59,12 @@ public abstract class AttributeUpdaterKernel {
executor.awaitTermination(1, TimeUnit.DAYS); executor.awaitTermination(1, TimeUnit.DAYS);
} }
endProcess(); writeLastExecutionDate();
statistic.stopTimer(); statistic.stopTimer();
statistic.printResult(); statistic.printResult();
} }
protected List<File> loadExcludedFiles() {
List<File> excludedFiles = InputConfig.getInstance().getExcludedDirectories().stream()
.map(collector::loadFiles)
.flatMap(Collection::stream)
.collect(Collectors.toList());
statistic.increaseTotalBy(excludedFiles.size());
statistic.increaseExcludedBy(excludedFiles.size());
return excludedFiles;
}
/**
* Load files or directories to update.
* Remove excluded directories.
*
* @param path Path to library
* @return List of files to update.
*/
abstract List<File> loadFiles(String path);
/** /**
* Start of the file updating process. * Start of the file updating process.
* This method is called by the executor and its contents are executed in parallel. * This method is called by the executor and its contents are executed in parallel.
@@ -96,24 +72,20 @@ public abstract class AttributeUpdaterKernel {
* @param file file or directory to update * @param file file or directory to update
*/ */
void process(File file) { void process(File file) {
FileInfo fileInfo = new FileInfo(file); FileInfo fileInfo = processor.readAttributes(file);
List<FileAttribute> attributes = processor.loadAttributes(file);
if (attributes == null || attributes.isEmpty()) { if (fileInfo.getTracks().isEmpty()) {
log.warn("No attributes found for file {}", file); log.warn("No attributes found for file {}", file);
statistic.total();
statistic.failure(); statistic.failure();
return; return;
} }
List<FileAttribute> nonForcedTracks = processor.retrieveNonForcedTracks(attributes); AttributeProcessor.findDefaultMatchAndApplyChanges(fileInfo);
List<FileAttribute> nonCommentaryTracks = processor.retrieveNonCommentaryTracks(attributes); AttributeProcessor.findForcedTracksAndApplyChanges(fileInfo);
AttributeProcessor.findCommentaryTracksAndApplyChanges(fileInfo);
AttributeProcessor.findHearingImpairedTracksAndApplyChanges(fileInfo);
processor.detectDefaultTracks(fileInfo, attributes, nonForcedTracks); checkStatusAndUpdate(fileInfo);
processor.detectDesiredTracks(fileInfo, nonForcedTracks, nonCommentaryTracks,
InputConfig.getInstance().getAttributeConfig().toArray(new AttributeConfig[]{}));
updateFile(fileInfo);
} }
/** /**
@@ -121,8 +93,7 @@ public abstract class AttributeUpdaterKernel {
* *
* @param fileInfo contains information about file and desired configuration. * @param fileInfo contains information about file and desired configuration.
*/ */
protected void updateFile(FileInfo fileInfo) { protected void checkStatusAndUpdate(FileInfo fileInfo) {
statistic.total();
switch (fileInfo.getStatus()) { switch (fileInfo.getStatus()) {
case CHANGE_NECESSARY: case CHANGE_NECESSARY:
statistic.shouldChange(); statistic.shouldChange();
@@ -142,12 +113,10 @@ public abstract class AttributeUpdaterKernel {
} }
private void commitChange(FileInfo fileInfo) { private void commitChange(FileInfo fileInfo) {
if (InputConfig.getInstance().isSafeMode()) { if (InputConfig.getInstance().isSafeMode()) return;
return;
}
try { try {
processor.update(fileInfo.getFile(), fileInfo); processor.update(fileInfo);
statistic.success(); statistic.success();
log.info("Commited {} to '{}'", fileInfo.getMatchedConfig().toStringShort(), fileInfo.getFile().getAbsolutePath()); log.info("Commited {} to '{}'", fileInfo.getMatchedConfig().toStringShort(), fileInfo.getFile().getAbsolutePath());
} catch (IOException | MkvToolNixException e) { } catch (IOException | MkvToolNixException e) {
@@ -156,7 +125,8 @@ public abstract class AttributeUpdaterKernel {
} }
} }
protected void endProcess() { // should this be here?
protected void writeLastExecutionDate() {
if (InputConfig.getInstance().isSafeMode()) { if (InputConfig.getInstance().isSafeMode()) {
return; return;
} }

View File

@@ -1,11 +1,8 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.kernel; package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.kernel;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.InputConfig; import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.InputConfig;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.FileCollector; import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.processors.FileProcessor;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.FileProcessor;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.AttributeConfig; import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.AttributeConfig;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.FileAttribute;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.FileInfo;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import me.tongfei.progressbar.ProgressBarBuilder; import me.tongfei.progressbar.ProgressBarBuilder;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@@ -17,8 +14,8 @@ import java.util.stream.Collectors;
@Slf4j @Slf4j
public class CoherentAttributeUpdaterKernel extends AttributeUpdaterKernel { public class CoherentAttributeUpdaterKernel extends AttributeUpdaterKernel {
public CoherentAttributeUpdaterKernel(FileCollector collector, FileProcessor processor) { public CoherentAttributeUpdaterKernel(FileProcessor processor) {
super(collector, processor); super(processor);
} }
@Override @Override
@@ -27,18 +24,10 @@ public class CoherentAttributeUpdaterKernel extends AttributeUpdaterKernel {
.setUnit(" directories", 1); .setUnit(" directories", 1);
} }
/**
* {@inheritDoc}
*/
@Override
List<File> loadFiles(String path) {
return loadFiles(path, InputConfig.getInstance().getCoherent());
}
List<File> loadFiles(String path, int depth) { List<File> loadFiles(String path, int depth) {
List<File> excludedFiles = loadExcludedFiles(); List<File> directories = processor.loadDirectories(path, depth)
List<File> directories = collector.loadDirectories(path, depth) .stream()
.stream().filter(file -> !excludedFiles.contains(file)) // .filter(file -> !excludedFiles.contains(file))
.collect(Collectors.toList()); .collect(Collectors.toList());
return directories.stream() return directories.stream()
.filter(dir -> isParentDirectory(dir, directories)) .filter(dir -> isParentDirectory(dir, directories))
@@ -67,43 +56,43 @@ public class CoherentAttributeUpdaterKernel extends AttributeUpdaterKernel {
void process(File file, int depth) { void process(File file, int depth) {
// TODO: Implement level crawl if coherence is not possible on user entered depth // TODO: Implement level crawl if coherence is not possible on user entered depth
// IMPL idea: recursive method call, cache needs to be implemented // IMPL idea: recursive method call, cache needs to be implemented
List<FileInfo> fileInfos = collector.loadFiles(file.getAbsolutePath()).stream() // List<FileInfoOld> fileInfoOlds = collector.loadFiles(file.getAbsolutePath()).stream()
.map(FileInfo::new) // .map(FileInfoOld::new)
.collect(Collectors.toList()); // .collect(Collectors.toList());
for (AttributeConfig config : InputConfig.getInstance().getAttributeConfig()) { for (AttributeConfig config : InputConfig.getInstance().getAttributeConfig()) {
for (FileInfo fileInfo : fileInfos) { // for (FileInfoOld fileInfoOld : fileInfoOlds) {
List<FileAttribute> attributes = processor.loadAttributes(fileInfo.getFile()); // List<TrackAttributes> attributes = processor.readAttributes(fileInfoOld.getFile());
//
// List<TrackAttributes> nonForcedTracks = processor.retrieveNonForcedTracks(attributes);
// List<TrackAttributes> nonCommentaryTracks = processor.retrieveNonCommentaryTracks(attributes);
//
// processor.detectDefaultTracks(fileInfoOld, attributes, nonForcedTracks);
// processor.detectDesiredTracks(fileInfoOld, nonForcedTracks, nonCommentaryTracks, config);
// }
//
// if (fileInfoOlds.stream().allMatch(elem -> ("OFF".equals(config.getSubtitleLanguage()) || elem.getDesiredDefaultSubtitleLane() != null)
// && elem.getDesiredDefaultAudioLane() != null)) {
// log.info("Found {} match for {}", config.toStringShort(), file.getAbsolutePath());
// fileInfoOlds.forEach(this::updateFile);
// return; // match found, end process here
// }
List<FileAttribute> nonForcedTracks = processor.retrieveNonForcedTracks(attributes); // fileInfoOlds.forEach(f -> {
List<FileAttribute> nonCommentaryTracks = processor.retrieveNonCommentaryTracks(attributes); // f.setDesiredDefaultAudioLane(null);
// f.setDesiredDefaultSubtitleLane(null);
processor.detectDefaultTracks(fileInfo, attributes, nonForcedTracks); // });
processor.detectDesiredTracks(fileInfo, nonForcedTracks, nonCommentaryTracks, config);
}
if (fileInfos.stream().allMatch(elem -> ("OFF".equals(config.getSubtitleLanguage()) || elem.getDesiredDefaultSubtitleLane() != null)
&& elem.getDesiredDefaultAudioLane() != null)) {
log.info("Found {} match for {}", config.toStringShort(), file.getAbsolutePath());
fileInfos.forEach(this::updateFile);
return; // match found, end process here
}
fileInfos.forEach(f -> {
f.setDesiredDefaultAudioLane(null);
f.setDesiredDefaultSubtitleLane(null);
});
} }
log.info("No coherent match found for {}", file.getAbsoluteFile()); log.info("No coherent match found for {}", file.getAbsoluteFile());
for (FileInfo fileInfo : fileInfos) { // for (FileInfoOld fileInfoOld : fileInfoOlds) {
if (!InputConfig.getInstance().isForceCoherent()) { // if (!InputConfig.getInstance().isForceCoherent()) {
super.process(fileInfo.getFile()); // super.process(fileInfoOld.getFile());
} else { // } else {
statistic.excluded(); // statistic.excluded();
} // }
} // }
} }
} }

View File

@@ -1,8 +1,7 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.kernel; package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.kernel;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.InputConfig; import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.InputConfig;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.FileCollector; import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.processors.FileProcessor;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.FileProcessor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import me.tongfei.progressbar.ProgressBarBuilder; import me.tongfei.progressbar.ProgressBarBuilder;
@@ -13,8 +12,8 @@ import java.util.stream.Collectors;
@Slf4j @Slf4j
public class DefaultAttributeUpdaterKernel extends AttributeUpdaterKernel { public class DefaultAttributeUpdaterKernel extends AttributeUpdaterKernel {
public DefaultAttributeUpdaterKernel(FileCollector collector, FileProcessor processor) { public DefaultAttributeUpdaterKernel(FileProcessor processor) {
super(collector, processor); super(processor);
} }
@Override @Override
@@ -22,15 +21,4 @@ public class DefaultAttributeUpdaterKernel extends AttributeUpdaterKernel {
return super.pbBuilder() return super.pbBuilder()
.setUnit(" files", 1); .setUnit(" files", 1);
} }
/**
* {@inheritDoc}
*/
@Override
List<File> loadFiles(String path) {
List<File> excludedFiles = loadExcludedFiles();
return collector.loadFiles(InputConfig.getInstance().getLibraryPath().getAbsolutePath()).stream()
.filter(file -> !excludedFiles.contains(file))
.collect(Collectors.toList());
}
} }

View File

@@ -0,0 +1,129 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.processors;
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 AttributeProcessor {
private static final SubtitleTrackComparator subtitleTrackComparator =
new SubtitleTrackComparator(InputConfig.getInstance().getPreferredSubtitles().toArray(new String[0]));
private static List<TrackAttributes> filterForPossibleDefaults(List<TrackAttributes> tracks) {
InputConfig config = InputConfig.getInstance();
Stream<TrackAttributes> attributes = tracks.stream();
if (true) { // TODO: config for including commentary
attributes = attributes
.filter(attr -> !attr.commentary())
.filter(attr -> {
if (attr.trackName() == null) return true;
return config.getCommentaryKeywords().stream().noneMatch(keyword -> keyword.compareToIgnoreCase(attr.trackName()) == 0);
});
}
if (true) { // TODO: config for including hearing impaired
attributes = attributes
.filter(attr -> !attr.hearingImpaired())
.filter(attr -> {
if (attr.trackName() == null) return true;
return config.getHearingImpaired().stream().noneMatch(keyword -> keyword.compareToIgnoreCase(attr.trackName()) == 0);
});;
}
return attributes
.filter(attr -> !attr.forced())
.filter(attr -> {
if (attr.trackName() == null) return true;
return config.getForcedKeywords().stream().noneMatch(keyword -> keyword.compareToIgnoreCase(attr.trackName()) == 0);
})
.toList();
}
public static void findDefaultMatchAndApplyChanges(FileInfo fileInfo) {
findDefaultMatchAndApplyChanges(fileInfo, InputConfig.getInstance().getAttributeConfig().toArray(new AttributeConfig[0]));
}
public static 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 static void applyDefaultChanges(FileInfo fileInfo, Function<FileInfo, List<TrackAttributes>> tracks, String language, Supplier<TrackAttributes> targetDefaultSupplier) {
tracks.apply(fileInfo).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);
}
}
}
public static void findForcedTracksAndApplyChanges(FileInfo fileInfo) {
Stream<TrackAttributes> forcedTracks = fileInfo.getTracks().stream()
.filter(track -> track.trackName() != null)
.filter(track -> InputConfig.getInstance().getForcedKeywords().stream().anyMatch(keyword -> track.trackName().toLowerCase().contains(keyword.toLowerCase(Locale.ROOT))));
if (InputConfig.getInstance().isOverwriteForced()) {
fileInfo.getTracks().stream().filter(TrackAttributes::forced).forEach(attr -> {
fileInfo.getChanges().getForcedTrack().put(attr, false);
});
} else {
forcedTracks = forcedTracks.filter(attr -> !attr.forced());
}
forcedTracks.forEach(attr -> {
fileInfo.getChanges().getForcedTrack().put(attr, true);
});
}
public static void findCommentaryTracksAndApplyChanges(FileInfo fileInfo) {
fileInfo.getTracks().stream()
.filter(track -> !track.commentary())
.filter(track -> track.trackName() != null)
.filter(track -> InputConfig.getInstance().getCommentaryKeywords().stream().anyMatch(keyword -> track.trackName().toLowerCase().contains(keyword.toLowerCase(Locale.ROOT))))
.forEach(attr -> {
fileInfo.getChanges().getCommentaryTrack().put(attr, true);
});
}
public static void findHearingImpairedTracksAndApplyChanges(FileInfo fileInfo) {
fileInfo.getTracks().stream()
.filter(track -> !track.commentary())
.filter(track -> track.trackName() != null)
.filter(track -> InputConfig.getInstance().getHearingImpaired().stream().anyMatch(keyword -> track.trackName().toLowerCase().contains(keyword.toLowerCase(Locale.ROOT))))
.forEach(attr -> {
fileInfo.getChanges().getHearingImpairedTrack().put(attr, true);
});
}
}

View File

@@ -0,0 +1,15 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.processors;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.Cache;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.FileInfo;
import java.io.File;
public class CachedMkvFileProcessor extends MkvFileProcessor {
Cache<File, FileInfo> cache = new Cache<>();
@Override
public FileInfo readAttributes(File file) {
return cache.retrieve(file, super::readAttributes);
}
}

View File

@@ -0,0 +1,44 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.processors;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.exceptions.MkvToolNixException;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.FileInfo;
import java.io.File;
import java.io.IOException;
import java.util.List;
public interface FileProcessor {
/**
* @param path leads to one file directly or a directory which will be loaded recursively
* @return list of all files within the directory
*/
List<File> loadFiles(String path);
/**
* Load all directories from path, but only until depth is reached.
* This will ignore all files between root and directories at depth.
*
* @param path leads to a directory which will be loaded recursively until depth
* @param depth limit directory crawling
* @return list of directory until depth
*/
List<File> loadDirectories(String path, int depth);
/**
* Load track information from file.
*
* @param file Takes the file from which the attributes will be returned
* @return list of all important attributes
*/
FileInfo readAttributes(File file);
/**
* Update the file.
*
* @param fileInfo information used to update file
* @throws IOException when error occurs accessing file retrieving information
* @throws MkvToolNixException when error occurs while sending query to mkvpropedit
*/
void update(FileInfo fileInfo) throws IOException, MkvToolNixException;
}

View File

@@ -0,0 +1,143 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.processors;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.FileFilter;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.SubtitleTrackComparator;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.InputConfig;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.exceptions.MkvToolNixException;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.*;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.util.SetUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.core.util.IOUtils;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.TrackType.AUDIO;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.TrackType.SUBTITLES;
import static java.lang.String.format;
@Slf4j
public class MkvFileProcessor implements FileProcessor {
private final ObjectMapper mapper = new ObjectMapper();
private static final Set<String> fileExtensions = new HashSet<>(Set.of(".mkv", ".mka", ".mks", ".mk3d"));
private static final String DEFAULT_TRACK = "--edit track:%s --set flag-default=%s";
private static final String FORCED_TRACK = "--edit track:%s --set flag-forced=%s";
private static final String COMMENTARY_TRACK = "--edit track:%s --set flag-commentary=%s";
private static final String HEARING_IMPAIRED_TRACK = "--edit track:%s --set flag-hearing-impaired=%s";
/**
* {@inheritDoc}
*/
@Override
public List<File> loadFiles(String path) {
try (Stream<Path> paths = Files.walk(Paths.get(path))) {
return paths
.filter(Files::isRegularFile)
.map(Path::toFile)
.filter(file -> FileFilter.accept(file, fileExtensions))
.collect(Collectors.toList());
} catch (IOException e) {
log.error("Couldn't find file or directory!", e);
return new ArrayList<>();
}
}
/**
* {@inheritDoc}
*/
@Override
// does this load /arst/arst & /arst ?
public List<File> loadDirectories(String path, int depth) {
try (Stream<Path> paths = Files.walk(Paths.get(path), depth)) {
return paths.map(Path::toFile)
.filter(File::isDirectory)
.collect(Collectors.toList());
} catch (IOException e) {
log.error("Couldn't find file or directory!", e);
return new ArrayList<>();
}
}
@SuppressWarnings("unchecked")
@Override
public FileInfo readAttributes(File file) {
FileInfo fileInfo = new FileInfo(file);
try {
String[] command = new String[]{
InputConfig.getInstance().getPathFor(MkvToolNix.MKV_MERGE),
"--identify",
"--identification-format",
"json",
file.getAbsolutePath()
};
log.debug("Executing: {}", String.join(" ", command));
InputStream inputStream = Runtime.getRuntime().exec(command)
.getInputStream();
Map<String, Object> jsonMap = mapper.readValue(inputStream, Map.class);
List<Map<String, Object>> tracks = (List<Map<String, Object>>) jsonMap.get("tracks");
if (tracks != null) {
for (Map<String, Object> attribute : tracks) {
if (!"video".equals(attribute.get("type"))) {
Map<String, Object> properties = (Map<String, Object>) attribute.get("properties");
fileInfo.getTracks().add(new TrackAttributes(
(int) properties.get("number"),
(String) properties.get("language"),
(String) properties.get("track_name"),
(Boolean) properties.getOrDefault("default_track", false),
(Boolean) properties.getOrDefault("forced_track", false),
(Boolean) properties.getOrDefault("commentary_track", false),
(Boolean) properties.getOrDefault("hearing_impaired_track", false),
TrackType.valueOf(((String) attribute.get("type")).toUpperCase(Locale.ENGLISH))));
}
}
} else {
log.warn("Couldn't retrieve information of {}", file.getAbsolutePath());
}
log.debug("File attributes of '{}': {}", file.getAbsolutePath(), fileInfo.getTracks());
} catch (IOException e) {
log.error("File could not be found or loaded: ", e);
System.out.println("File could not be found or loaded: " + file.getAbsolutePath());
}
return fileInfo;
}
/**
* {@inheritDoc}
*/
@Override
public void update(FileInfo fileInfo) throws IOException, MkvToolNixException {
List<String> command = new ArrayList<>();
command.add(InputConfig.getInstance().getPathFor(MkvToolNix.MKV_PROP_EDIT));
command.add(String.format(fileInfo.getFile().getAbsolutePath()));
PlannedChange changes = fileInfo.getChanges();
changes.getDefaultTrack().forEach((key, value) -> command.addAll(format(DEFAULT_TRACK, key.id(), value ? 1 : 0)));
changes.getForcedTrack().forEach((key, value) -> command.addAll(format(FORCED_TRACK, key.id(), value ? 1 : 0)));
changes.getCommentaryTrack().forEach((key, value) -> command.addAll(format(COMMENTARY_TRACK, key.id(), value ? 1 : 0)));
changes.getHearingImpairedTrack().forEach((key, value) -> command.addAll(format(HEARING_IMPAIRED_TRACK, key.id(), value ? 1 : 0)));
log.debug("Executing '{}'", String.join(" ", command));
InputStream inputstream = Runtime.getRuntime().exec(command.toArray(new String[0])).getInputStream();
String output = IOUtils.toString(new InputStreamReader(inputstream));
log.debug("Result: {}", output);
if (output.contains("Error")) throw new MkvToolNixException(output);
}
private List<String> format(String format, Object... args) {
return Arrays.asList(String.format(format, args).split(" "));
}
}

View File

@@ -1,4 +1,4 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validation; package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.validation;
import jakarta.validation.Constraint; import jakarta.validation.Constraint;
import jakarta.validation.Payload; import jakarta.validation.Payload;

View File

@@ -1,4 +1,4 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validation; package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.validation;
import jakarta.validation.ConstraintValidator; import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext; import jakarta.validation.ConstraintValidatorContext;

View File

@@ -1,4 +1,4 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validation; package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.validation;
import jakarta.validation.Constraint; import jakarta.validation.Constraint;
import jakarta.validation.Payload; import jakarta.validation.Payload;

View File

@@ -1,4 +1,4 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validation; package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.validation;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.MkvToolNix; import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.MkvToolNix;
import jakarta.validation.ConstraintValidator; import jakarta.validation.ConstraintValidator;

View File

@@ -1,7 +1,7 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validation; package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.validation;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.Main; import at.pcgamingfreaks.mkvaudiosubtitlechanger.Main;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.InputConfig; import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.InputConfig;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.util.ValidationUtil; import at.pcgamingfreaks.mkvaudiosubtitlechanger.util.ValidationUtil;
import jakarta.validation.ConstraintViolation; import jakarta.validation.ConstraintViolation;
import jakarta.validation.Validator; import jakarta.validation.Validator;
@@ -12,8 +12,8 @@ import java.util.Set;
public class ValidationExecutionStrategy implements CommandLine.IExecutionStrategy { public class ValidationExecutionStrategy implements CommandLine.IExecutionStrategy {
public int execute(CommandLine.ParseResult parseResult) { public int execute(CommandLine.ParseResult parseResult) {
validate(parseResult.commandSpec()); if (!parseResult.isVersionHelpRequested() && !parseResult.isUsageHelpRequested()) validate(parseResult.commandSpec());
return new CommandLine.RunLast().execute(parseResult); // default execution strategy return new CommandLine.RunLast().execute(parseResult);
} }
private static void validate(CommandLine.Model.CommandSpec spec) { private static void validate(CommandLine.Model.CommandSpec spec) {

View File

@@ -1,68 +0,0 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.model;
import lombok.AllArgsConstructor;
import org.apache.commons.cli.Option;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;
@AllArgsConstructor
public enum ConfigProperty {
LIBRARY("library-path", "Path to library", "l", 1),
ATTRIBUTE_CONFIG("attribute-config", "Attribute config to decide which tracks to choose when", "a", Option.UNLIMITED_VALUES),
CONFIG_PATH("config-path", "Path to config file", "p", 1),
MKV_TOOL_NIX("mkvtoolnix", "Path to mkv tool nix installation", "m", 1),
SAFE_MODE("safe-mode", "Test run (no files will be changes)", "s", 0),
COHERENT("coherent", "Try to match all files in dir of depth with the same config", "c", 1),
FORCE_COHERENT("force-coherent", "Force coherent and don't update anything if config fits not whole config (default: false)", "cf", 0),
WINDOWS("windows", "Is operating system windows", null, 0),
ONLY_NEW_FILES("only-new-files", "Sets filter-date to last successful execution (Overwrites input of filter-date)", "n", 0),
FILTER_DATE("filter-date", "Only consider files created newer than entered date (format: \"dd.MM.yyyy-HH:mm:ss\")", "d", 1),
THREADS("threads", "Thread count (default: 2)", "t", 1),
INCLUDE_PATTERN("include-pattern", "Include files matching pattern (default: \".*\")", "i", 1),
EXCLUDED_DIRECTORY("excluded-directories", "Directories to be excluded, combines with config file", "e", Option.UNLIMITED_VALUES),
FORCED_KEYWORDS("forced-keywords", "Additional keywords to identify forced tracks", "fk", Option.UNLIMITED_VALUES),
COMMENTARY_KEYWORDS("commentary-keywords", "Additional keywords to identify commentary tracks", "ck", Option.UNLIMITED_VALUES),
PREFERRED_SUBTITLES("preferred-subtitles", "Additional keywords to prefer specific subtitle tracks", "ps", Option.UNLIMITED_VALUES),
ARGUMENTS("arguments", "List of arguments", null, 0),
VERSION("version", "Display version", "v", 0),
HELP("help", "\"For help this is\" - Yoda", "h", 0);
/*
* Verify at startup that there are no duplicated shortParameters.
*/
static {
Set<String> shortParameters = new HashSet<>();
for (String param : Arrays.stream(ConfigProperty.values()).map(ConfigProperty::abrv).collect(Collectors.toList())) {
if (shortParameters.contains(param)) {
throw new IllegalStateException("It is not allowed to have multiple properties with the same abbreviation!");
}
if (param != null) {
shortParameters.add(param);
}
}
}
private final String property;
private final String description;
private final String shortParameter;
private final int args;
public String prop() {
return property;
}
public String desc() {
return description;
}
public String abrv() {
return shortParameter;
}
public int args() {
return args;
}
}

View File

@@ -5,80 +5,38 @@ import lombok.RequiredArgsConstructor;
import lombok.Setter; import lombok.Setter;
import java.io.File; import java.io.File;
import java.util.HashSet; import java.util.ArrayList;
import java.util.Set; import java.util.Collection;
import java.util.function.Function; import java.util.List;
@Getter @Getter
@Setter
@RequiredArgsConstructor @RequiredArgsConstructor
public class FileInfo { public class FileInfo {
private final File file; private final File file;
private Set<FileAttribute> existingDefaultAudioLanes = new HashSet<>(); private final List<TrackAttributes> tracks = new ArrayList<>();
private Set<FileAttribute> existingForcedAudioLanes = new HashSet<>();
private Set<FileAttribute> existingDefaultSubtitleLanes = new HashSet<>(); private final List<TrackAttributes> audioTracks = new ArrayList<>();
private Set<FileAttribute> existingForcedSubtitleLanes = new HashSet<>(); private final List<TrackAttributes> subtitleTracks = new ArrayList<>();
private Set<FileAttribute> desiredForcedSubtitleLanes = new HashSet<>(); private final PlannedChange changes = new PlannedChange();
private FileAttribute desiredDefaultAudioLane; @Setter
private FileAttribute desiredDefaultSubtitleLane;
private AttributeConfig matchedConfig; private AttributeConfig matchedConfig;
public boolean isAudioDifferent() { public void addTrack(TrackAttributes track) {
return isMatchDifferent(existingDefaultAudioLanes, desiredDefaultAudioLane) tracks.add(track);
|| isLaneOff(existingDefaultAudioLanes, desiredDefaultAudioLane, AttributeConfig::getAudioLanguage); if (TrackType.AUDIO.equals(track.type())) audioTracks.add(track);
else if (TrackType.SUBTITLES.equals(track.type())) subtitleTracks.add(track);
} }
public boolean isSubtitleDifferent() { public void addTracks(Collection<TrackAttributes> tracks) {
return isMatchDifferent(existingDefaultSubtitleLanes, desiredDefaultSubtitleLane) for (TrackAttributes track : tracks) addTrack(track);
|| isLaneOff(existingDefaultSubtitleLanes, desiredDefaultSubtitleLane, AttributeConfig::getSubtitleLanguage);
}
private boolean isMatchDifferent(Set<FileAttribute> existingDefault, FileAttribute desiredDefault) {
return desiredDefault != null &&
(existingDefault == null || !existingDefault.contains(desiredDefault) || existingDefault.size() > 1);
}
private boolean isLaneOff(Set<FileAttribute> existingDefault, FileAttribute desiredDefault, Function<AttributeConfig, String> inputLane) {
return desiredDefault == null
&& (matchedConfig != null && "OFF".equals(inputLane.apply(matchedConfig)))
&& (existingDefault != null && !existingDefault.isEmpty());
}
public boolean areForcedTracksDifferent() {
return !desiredForcedSubtitleLanes.isEmpty() && !existingForcedSubtitleLanes.containsAll(desiredForcedSubtitleLanes);
} }
public FileStatus getStatus() { public FileStatus getStatus() {
if (isChangeNecessary()) return FileStatus.CHANGE_NECESSARY; if (!changes.isEmpty()) return FileStatus.CHANGE_NECESSARY;
if (isUnableToApplyConfig()) return FileStatus.NO_SUITABLE_CONFIG; if (matchedConfig == null) return FileStatus.NO_SUITABLE_CONFIG;
if (isAlreadySuited()) return FileStatus.ALREADY_SUITED; if (changes.isEmpty()) return FileStatus.ALREADY_SUITED;
return FileStatus.UNKNOWN; return FileStatus.UNKNOWN;
} }
private boolean isUnableToApplyConfig() {
return desiredDefaultAudioLane == null && !"OFF".equals(matchedConfig.getAudioLanguage())
&& desiredDefaultSubtitleLane == null && !"OFF".equals(matchedConfig.getSubtitleLanguage());
}
private boolean isAlreadySuited() {
return (desiredDefaultAudioLane == null || existingDefaultAudioLanes.contains(desiredDefaultAudioLane))
&& (desiredDefaultSubtitleLane == null || existingDefaultSubtitleLanes.contains(desiredDefaultSubtitleLane));
}
private boolean isChangeNecessary() {
return isAudioDifferent() || isSubtitleDifferent() || areForcedTracksDifferent() || !existingForcedAudioLanes.isEmpty();
}
@Override
public String toString() {
return "[" + "defaultAudioLanes=" + existingDefaultAudioLanes +
", defaultSubtitleLanes=" + existingDefaultSubtitleLanes +
", desiredForcedSubtitleLanes=" + desiredForcedSubtitleLanes +
", desiredAudioLane=" + desiredDefaultAudioLane +
", desiredSubtitleLane=" + desiredDefaultSubtitleLane +
']';
}
} }

View File

@@ -1,10 +1,8 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.config; package at.pcgamingfreaks.mkvaudiosubtitlechanger.model;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.converter.AttributeConfigConverter; import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.converter.AttributeConfigConverter;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validation.ValidFile; import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.validation.ValidFile;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validation.ValidMkvToolNix; import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.validation.ValidMkvToolNix;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.AttributeConfig;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.MkvToolNix;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.util.FileUtils; import at.pcgamingfreaks.mkvaudiosubtitlechanger.util.FileUtils;
import jakarta.validation.constraints.Min; import jakarta.validation.constraints.Min;
import lombok.AccessLevel; import lombok.AccessLevel;
@@ -38,18 +36,16 @@ public class InputConfig {
@Option(names = {"-a", "--attribute-config"}, required = true, arity = "1..*", converter = AttributeConfigConverter.class, @Option(names = {"-a", "--attribute-config"}, required = true, arity = "1..*", converter = AttributeConfigConverter.class,
description = "List of audio:subtitle pairs used to match in order and update files accordingly (e.g. jpn:eng jpn:ger)") description = "List of audio:subtitle pairs used to match in order and update files accordingly (e.g. jpn:eng jpn:ger)")
private List<AttributeConfig> attributeConfig; private List<AttributeConfig> attributeConfig;
@ValidFile(message = "does not exist") @ValidFile(message = "does not exist")
@Option(names = {"-l", "--library"}, required = true, description = "path to library") @Option(names = {"-l", "--library"}, required = true, description = "path to library")
private File libraryPath; private File libraryPath;
@Option(names = {"-s", "--safemode"}, description = "test run (no files will be changes)")
private boolean safeMode;
@ValidMkvToolNix(message = "does not exist") @ValidMkvToolNix(message = "does not exist")
@Option(names = {"-m", "--mkvtoolnix"}, defaultValue = "${DEFAULT_MKV_TOOL_NIX}", description = "path to mkvtoolnix installation") @Option(names = {"-m", "--mkvtoolnix"}, defaultValue = "${DEFAULT_MKV_TOOL_NIX}", description = "path to mkvtoolnix installation")
private File mkvToolNix; private File mkvToolNix;
@Option(names = {"-s", "--safemode"}, description = "test run (no files will be changes)")
private boolean safeMode;
@Min(1) @Min(1)
@Option(names = {"-t", "--threads"}, defaultValue = "2", description = "thread count (default: ${DEFAULT-VALUE})") @Option(names = {"-t", "--threads"}, defaultValue = "2", description = "thread count (default: ${DEFAULT-VALUE})")
private int threads; private int threads;
@@ -57,35 +53,34 @@ public class InputConfig {
@Min(0) @Min(0)
@Option(names = {"-c", "--coherent"}, description = "try to match all files in dir of depth with the same attribute config") @Option(names = {"-c", "--coherent"}, description = "try to match all files in dir of depth with the same attribute config")
private Integer coherent; private Integer coherent;
@Option(names = {"-cf", "--force-coherent"}, description = "changes are only applied if it's a coherent match") @Option(names = {"-cf", "--force-coherent"}, description = "changes are only applied if it's a coherent match")
private boolean forceCoherent; private boolean forceCoherent;
@Option(names = {"-n", "--only-new-file"}, description = "sets filter-date to last successful execution (overwrites input of filter-date)") @Option(names = {"-n", "--only-new-file"}, description = "sets filter-date to last successful execution (overwrites input of filter-date)")
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 (format: \"dd.MM.yyyy-HH:mm:ss\")")
private Date filterDate; private Date filterDate;
@Option(names = {"-i", "--include-pattern"}, defaultValue = ".*", description = "include files matching pattern (default: \".*\")") @Option(names = {"-i", "--include-pattern"}, defaultValue = ".*", description = "include files matching pattern (default: \".*\")")
private Pattern includePattern; private Pattern includePattern;
@Option(names = {"-e", "--excluded"}, arity = "1..*",
description = "Directories and files to be excluded (no wildcard)")
private Set<String> excluded = new HashSet<>();
@Option(names = {"-e", "--excluded-directory"}, arity = "1..*",
description = "Directories to be excluded, combines with config file")
private Set<String> excludedDirectories = new HashSet<>();
@Option(names = {"-o", "-overwrite-forced"}, description = "remove all forced flags")
private boolean overwriteForced;
@Option(names = {"--forced-keywords"}, arity = "1..*", defaultValue = "forced, signs, songs", split = ", ", @Option(names = {"--forced-keywords"}, arity = "1..*", defaultValue = "forced, signs, songs", split = ", ",
description = "Keywords to identify forced tracks (Defaults will be overwritten; Default: ${DEFAULT-VALUE})") description = "Keywords to identify forced tracks (Defaults will be overwritten; Default: ${DEFAULT-VALUE})")
private Set<String> forcedKeywords; private Set<String> forcedKeywords;
@Option(names = {"--commentary-keywords"}, arity = "1..*", defaultValue = "comment, commentary, director", split = ", ",
@Option(names = {"--commentary-keywords"}, arity = "1..*", defaultValue = "commentary, director", split = ", ",
description = "Keywords to identify commentary tracks (Defaults will be overwritten; Default: ${DEFAULT-VALUE})") description = "Keywords to identify commentary tracks (Defaults will be overwritten; Default: ${DEFAULT-VALUE})")
private Set<String> commentaryKeywords; private Set<String> commentaryKeywords;
@Option(names = {"--hearing-impaired"}, arity = "1..*", defaultValue = "SDH", split = ", ",
description = "Keywords to identify hearing impaired tracks (Defaults will be overwritten; Default: ${DEFAULT-VALUE}")
private Set<String> hearingImpaired;
@Option(names = {"--preferred-subtitles"}, arity = "1..*", defaultValue = "unstyled", split = ", ", @Option(names = {"--preferred-subtitles"}, arity = "1..*", defaultValue = "unstyled", split = ", ",
description = "Keywords to prefer specific subtitle tracks (Defaults will be overwritten; Default: ${DEFAULT-VALUE})") description = "Keywords to prefer specific subtitle tracks (Defaults will be overwritten; Default: ${DEFAULT-VALUE})")
private Set<String> preferredSubtitles; private Set<String> preferredSubtitles;
@Option(names = {"--debug"}, description = "Enable debug logging") @Option(names = {"--debug"}, description = "Enable debug logging")
private boolean debug; private boolean debug;
@@ -136,7 +131,7 @@ public class InputConfig {
.add("filterDate=" + filterDate) .add("filterDate=" + filterDate)
.add("forcedKeywords=" + forcedKeywords) .add("forcedKeywords=" + forcedKeywords)
.add("commentaryKeywords=" + commentaryKeywords) .add("commentaryKeywords=" + commentaryKeywords)
.add("excludedDirectories=" + excludedDirectories) .add("excludedDirectories=" + excluded)
.add("preferredSubtitles=" + preferredSubtitles) .add("preferredSubtitles=" + preferredSubtitles)
.add("attributeConfig=" + attributeConfig) .add("attributeConfig=" + attributeConfig)
.toString(); .toString();

View File

@@ -0,0 +1,18 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.model;
import lombok.Getter;
import java.util.HashMap;
import java.util.Map;
@Getter
public class PlannedChange {
private final Map<TrackAttributes, Boolean> defaultTrack = new HashMap<>();
private final Map<TrackAttributes, Boolean> forcedTrack = new HashMap<>();
private final Map<TrackAttributes, Boolean> commentaryTrack = new HashMap<>();
private final Map<TrackAttributes, Boolean> hearingImpairedTrack = new HashMap<>();
public boolean isEmpty() {
return defaultTrack.isEmpty() && forcedTrack.isEmpty() && commentaryTrack.isEmpty() && hearingImpairedTrack.isEmpty();
}
}

View File

@@ -17,7 +17,7 @@ public class ResultStatistic {
"└─ Failed: %s%n" + "└─ Failed: %s%n" +
"Runtime: %s"; "Runtime: %s";
private static ResultStatistic instance; private static ResultStatistic instance;
private int filesTotal = 0; private int total = 0;
private int excluded = 0; private int excluded = 0;
private int shouldChange = 0; private int shouldChange = 0;
@@ -33,18 +33,22 @@ public class ResultStatistic {
private long runtime = 0; private long runtime = 0;
public static ResultStatistic getInstance() { public static ResultStatistic getInstance() {
if (instance == null) { return getInstance(false);
}
public static ResultStatistic getInstance(boolean reset) {
if (instance == null || reset) {
instance = new ResultStatistic(); instance = new ResultStatistic();
} }
return instance; return instance;
} }
public void increaseTotalBy(int amount) { public void increaseTotalBy(int amount) {
filesTotal += amount; total += amount;
} }
public synchronized void total() { public synchronized void total() {
filesTotal++; total++;
} }
public void increaseExcludedBy(int amount) { public void increaseExcludedBy(int amount) {
@@ -110,13 +114,13 @@ public class ResultStatistic {
} }
public String prettyPrint() { public String prettyPrint() {
return String.format(result, filesTotal, excluded, shouldChange, failedChanging, successfullyChanged, return String.format(result, total, excluded, shouldChange, failedChanging, successfullyChanged,
noSuitableConfigFound, alreadyFits, failed, formatTimer()); noSuitableConfigFound, alreadyFits, failed, formatTimer());
} }
@Override @Override
public String toString() { public String toString() {
return "ResultStatistic: " + "filesTotal=" + filesTotal + return "ResultStatistic: " + "total=" + total +
", excluded=" + excluded + ", excluded=" + excluded +
", shouldChange=" + shouldChange + ", shouldChange=" + shouldChange +
" (failedChanging=" + failedChanging + " (failedChanging=" + failedChanging +

View File

@@ -5,16 +5,17 @@ import lombok.extern.slf4j.Slf4j;
import java.util.Objects; import java.util.Objects;
@Slf4j @Slf4j
public record FileAttribute(int id, String language, String trackName, boolean defaultTrack, boolean forcedTrack, public record TrackAttributes(int id, String language, String trackName,
LaneType type) { boolean defaultt, boolean forced, boolean commentary, boolean hearingImpaired,
TrackType type) {
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
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;
FileAttribute attribute = (FileAttribute) o; TrackAttributes attribute = (TrackAttributes) o;
return id == attribute.id return id == attribute.id
&& defaultTrack == attribute.defaultTrack && defaultt == attribute.defaultt
&& forcedTrack == attribute.forcedTrack && forced == attribute.forced
&& Objects.equals(language, attribute.language) && Objects.equals(language, attribute.language)
&& Objects.equals(trackName, attribute.trackName) && Objects.equals(trackName, attribute.trackName)
&& type == attribute.type; && type == attribute.type;
@@ -25,8 +26,8 @@ public record FileAttribute(int id, String language, String trackName, boolean d
return "[" + "id=" + id + return "[" + "id=" + id +
", language='" + language + '\'' + ", language='" + language + '\'' +
", trackName='" + trackName + '\'' + ", trackName='" + trackName + '\'' +
", defaultTrack=" + defaultTrack + ", defaultt=" + defaultt +
", forcedTrack=" + forcedTrack + ", forced=" + forced +
", type=" + type + ", type=" + type +
']'; ']';
} }

View File

@@ -1,6 +1,6 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.model; package at.pcgamingfreaks.mkvaudiosubtitlechanger.model;
public enum LaneType { public enum TrackType {
AUDIO, AUDIO,
SUBTITLES; SUBTITLES;
} }

View File

@@ -1,5 +1,6 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.converter; package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.converter;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.converter.AttributeConfigConverter;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.AttributeConfig; import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.AttributeConfig;
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;

View File

@@ -1,7 +1,7 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.fields; package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.fields;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.Main; import at.pcgamingfreaks.mkvaudiosubtitlechanger.Main;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.InputConfig; import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.InputConfig;
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;
import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.MethodSource;

View File

@@ -1,15 +1,13 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.fields; package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.fields;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.Main; import at.pcgamingfreaks.mkvaudiosubtitlechanger.Main;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.InputConfig; import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.InputConfig;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
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;
import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.MethodSource;
import picocli.CommandLine; import picocli.CommandLine;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Stream; import java.util.stream.Stream;

View File

@@ -1,7 +1,7 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.fields; package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.fields;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.Main; import at.pcgamingfreaks.mkvaudiosubtitlechanger.Main;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.InputConfig; import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.InputConfig;
import org.apache.commons.lang3.SystemUtils; import org.apache.commons.lang3.SystemUtils;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.ParameterizedTest;

View File

@@ -1,7 +1,7 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.fields; package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.fields;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.Main; import at.pcgamingfreaks.mkvaudiosubtitlechanger.Main;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.InputConfig; import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.InputConfig;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
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;

View File

@@ -1,7 +1,7 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.fields; package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.fields;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.Main; import at.pcgamingfreaks.mkvaudiosubtitlechanger.Main;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.InputConfig; import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.InputConfig;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
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;

View File

@@ -1,7 +1,7 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.fields; package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.fields;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.Main; import at.pcgamingfreaks.mkvaudiosubtitlechanger.Main;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.InputConfig; import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.InputConfig;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
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;

View File

@@ -1,6 +1,7 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl; package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.InputConfig; import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.InputConfig;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ResultStatistic;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.util.DateUtils; 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;
@@ -16,7 +17,9 @@ import java.io.File;
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.util.Date;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Stream; import java.util.stream.Stream;
@@ -34,38 +37,44 @@ class FileFilterTest {
@BeforeEach @BeforeEach
void beforeEach() { void beforeEach() {
ResultStatistic.getInstance(true);
} }
private static Stream<Arguments> accept() { private static Stream<Arguments> accept() {
return Stream.of( return Stream.of(
Arguments.of("~/video.mkv", new String[]{".mkv"}, null, null, ".*", true), Arguments.of("~/video.mkv", Set.of(".mkv"), -1, ".*", true, 1, 0),
Arguments.of("~/video.mp4", new String[]{".mkv"}, null, null, ".*", false), Arguments.of("~/video.mp4", Set.of(".mkv"), -1, ".*", false, 0, 0),
Arguments.of("~/video.mkv", new String[]{".mkv"}, null, null, "v.*", true), Arguments.of("~/video.mkv", Set.of(".mkv"), -1, "v.*", true, 1, 0),
Arguments.of("~/video.mkv", new String[]{".mkv"}, null, null, "a.*", false), Arguments.of("~/video.mkv", Set.of(".mkv"), -1, "a.*", false, 1, 1),
Arguments.of("~/video.mkv", new String[]{".mkv"}, new Date(System.currentTimeMillis() - 1000), new Date(), ".*", false), Arguments.of("~/video.mkv", Set.of(".mkv"), -1000, ".*", true, 1, 0),
Arguments.of("~/video.mkv", new String[]{".mkv"}, new Date(), new Date(System.currentTimeMillis() - 1000), ".*", true) Arguments.of("~/video.mkv", Set.of(".mkv"), 1000, ".*", false, 1, 1)
); );
} }
/**
* @param filterDateOffset move filter data into the future or past by positive and negative values
*/
@ParameterizedTest @ParameterizedTest
@MethodSource @MethodSource
void accept(String path, String[] args, Date fileCreationDate, Date filterDate, String pattern, boolean expected) { void accept(String path, Set<String> args, int filterDateOffset, String pattern, boolean expectedHit, int total, int excluded) {
when(file.getAbsolutePath()).thenReturn(path); when(file.getAbsolutePath()).thenReturn(path);
when(file.getName()).thenReturn(List.of(path.split("/")).get(1)); when(file.getName()).thenReturn(List.of(path.split("/")).get(1));
when(file.toPath()).thenReturn(Path.of(TEST_FILE)); when(file.toPath()).thenReturn(Path.of(TEST_FILE));
InputConfig.getInstance(true).setIncludePattern(Pattern.compile(pattern)); InputConfig.getInstance(true).setIncludePattern(Pattern.compile(pattern));
if (filterDate != null) InputConfig.getInstance().setFilterDate(filterDate); long currentTime = System.currentTimeMillis();
InputConfig.getInstance().setFilterDate(new Date(currentTime + filterDateOffset));
try (MockedStatic<DateUtils> mockedFiles = Mockito.mockStatic(DateUtils.class)) { try (MockedStatic<DateUtils> mockedFiles = Mockito.mockStatic(DateUtils.class)) {
mockedFiles mockedFiles
.when(() -> DateUtils.convert(anyLong())) .when(() -> DateUtils.convert(anyLong()))
.thenReturn(fileCreationDate); .thenReturn(new Date(currentTime));
assertEquals(expected, FileFilter.accept(file, args)); assertEquals(expectedHit, FileFilter.accept(file, new HashSet<>(args)), "File is accepted");
assertEquals(total, ResultStatistic.getInstance().getTotal(), "Total files");
assertEquals(excluded, ResultStatistic.getInstance().getExcluded(), "Excluded files");
} }
} }
} }

View File

@@ -1,9 +1,11 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl; package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.InputConfig; import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.processors.MkvFileProcessor;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.AttributeConfig;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.FileAttribute;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.FileInfo; import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.FileInfo;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.InputConfig;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.AttributeConfig;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.TrackAttributes;
import org.junit.jupiter.api.Disabled;
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;
import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.MethodSource;
@@ -29,11 +31,12 @@ class MkvFileProcessorTest {
@ParameterizedTest @ParameterizedTest
@MethodSource @MethodSource
void detectDesiredTracks(AttributeConfig expectedMatch, List<FileAttribute> tracks, AttributeConfig... configs) { @Disabled
void detectDesiredTracks(AttributeConfig expectedMatch, List<TrackAttributes> tracks, AttributeConfig... configs) {
InputConfig.getInstance().setPreferredSubtitles(Set.of()); InputConfig.getInstance().setPreferredSubtitles(Set.of());
FileInfo info = new FileInfo(null); FileInfo info = new FileInfo(null);
MkvFileProcessor processor = new MkvFileProcessor(); MkvFileProcessor processor = new MkvFileProcessor();
processor.detectDesiredTracks(info, tracks, tracks, configs); // processor.detectDesiredTracks(info, tracks, tracks, configs);
assertEquals(expectedMatch.getAudioLanguage(), info.getMatchedConfig().getAudioLanguage()); assertEquals(expectedMatch.getAudioLanguage(), info.getMatchedConfig().getAudioLanguage());
assertEquals(expectedMatch.getSubtitleLanguage(), info.getMatchedConfig().getSubtitleLanguage()); assertEquals(expectedMatch.getSubtitleLanguage(), info.getMatchedConfig().getSubtitleLanguage());
} }
@@ -48,43 +51,4 @@ class MkvFileProcessorTest {
Arguments.of(List.of(), List.of()) Arguments.of(List.of(), List.of())
); );
} }
@ParameterizedTest
@MethodSource
void retrieveNonForcedTracks(List<FileAttribute> attributes, List<FileAttribute> expected) {
InputConfig.getInstance().setPreferredSubtitles(Set.of());
InputConfig.getInstance().setForcedKeywords(Set.of("forced"));
MkvFileProcessor processor = new MkvFileProcessor();
List<FileAttribute> actual = processor.retrieveNonForcedTracks(attributes);
assertEquals(expected.size(), actual.size());
for (int i = 0; i < expected.size(); i++) {
assertEquals(expected.get(i), actual.get(i));
}
}
private static Stream<Arguments> retrieveNonCommentaryTracks() {
return Stream.of(
Arguments.of(List.of(SUB_GER, SUB_ENG, AUDIO_GER_COMMENTARY), List.of(SUB_GER, SUB_ENG)),
Arguments.of(List.of(SUB_GER, SUB_ENG), List.of(SUB_GER, SUB_ENG)),
Arguments.of(List.of(AUDIO_GER, SUB_GER, SUB_ENG), List.of(AUDIO_GER, SUB_GER, SUB_ENG)),
Arguments.of(List.of(AUDIO_GER), List.of(AUDIO_GER)),
Arguments.of(List.of(AUDIO_GER_COMMENTARY), List.of()),
Arguments.of(List.of(), List.of())
);
}
@ParameterizedTest
@MethodSource
void retrieveNonCommentaryTracks(List<FileAttribute> attributes, List<FileAttribute> expected) {
InputConfig.getInstance().setPreferredSubtitles(Set.of());
InputConfig.getInstance().setCommentaryKeywords(Set.of("commentary"));
MkvFileProcessor processor = new MkvFileProcessor();
List<FileAttribute> actual = processor.retrieveNonCommentaryTracks(attributes);
assertEquals(expected.size(), actual.size());
for (int i = 0; i < expected.size(); i++) {
assertEquals(expected.get(i), actual.get(i));
}
}
} }

View File

@@ -1,7 +1,7 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl; package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.FileAttribute; import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.TrackAttributes;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.LaneType; import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.TrackType;
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;
import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.MethodSource;
@@ -34,13 +34,13 @@ class SubtitleTrackComparatorTest {
@ParameterizedTest @ParameterizedTest
@MethodSource("compareArguments") @MethodSource("compareArguments")
void compare(List<FileAttribute> input, List<FileAttribute> expected) { void compare(List<TrackAttributes> input, List<TrackAttributes> expected) {
List<FileAttribute> result = input.stream().sorted(comparator.reversed()).collect(Collectors.toList()); List<TrackAttributes> result = input.stream().sorted(comparator.reversed()).collect(Collectors.toList());
assertArrayEquals(expected.toArray(new FileAttribute[0]), result.toArray(new FileAttribute[0])); assertArrayEquals(expected.toArray(new TrackAttributes[0]), result.toArray(new TrackAttributes[0]));
} }
private static FileAttribute attr(String trackName, boolean defaultTrack) { private static TrackAttributes attr(String trackName, boolean defaultTrack) {
return new FileAttribute(0, "", trackName, defaultTrack, false, LaneType.SUBTITLES); return new TrackAttributes(0, "", trackName, defaultTrack, false, false, false, TrackType.SUBTITLES);
} }
} }

View File

@@ -0,0 +1,238 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.processors;
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.logging.log4j.util.Strings;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Stream;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.FileInfoTestUtil.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
class AttributeProcessorTest {
private static Stream<Arguments> attributeConfigMatching() {
return Stream.of(
Arguments.of(
List.of(withName(AUDIO_ENG, null), SUB_ENG),
arr(a("eng:eng")), "eng:eng",
Map.ofEntries(on(withName(AUDIO_ENG, null)), on(SUB_ENG))
),
Arguments.of(
List.of(AUDIO_ENG, SUB_ENG),
arr(a("eng:eng")), "eng:eng",
Map.ofEntries(on(AUDIO_ENG), on(SUB_ENG))
),
Arguments.of(
List.of(AUDIO_ENG, AUDIO_GER, SUB_ENG, SUB_GER),
arr(a("eng:eng")), "eng:eng",
Map.ofEntries(on(AUDIO_ENG), on(SUB_ENG))
),
Arguments.of(
List.of(AUDIO_ENG_DEFAULT, AUDIO_GER, SUB_ENG, SUB_GER),
arr(a("ger:eng")), "ger:eng",
Map.ofEntries(off(AUDIO_ENG_DEFAULT), on(AUDIO_GER), on(SUB_ENG))
),
Arguments.of(
List.of(AUDIO_ENG_DEFAULT, AUDIO_GER, SUB_ENG, SUB_GER),
arr(a("eng:ger")), "eng:ger",
Map.ofEntries(on(SUB_GER))
),
Arguments.of(
List.of(AUDIO_ENG_DEFAULT, AUDIO_GER, SUB_ENG_DEFAULT, SUB_GER),
arr(a("eng:OFF")), "eng:OFF",
Map.ofEntries(off(SUB_ENG_DEFAULT))
),
Arguments.of(
List.of(AUDIO_ENG_DEFAULT, AUDIO_GER, SUB_ENG_DEFAULT, SUB_GER),
arr(a("OFF:OFF")), "OFF:OFF",
Map.ofEntries(off(AUDIO_ENG_DEFAULT), off(SUB_ENG_DEFAULT))
),
Arguments.of(
List.of(AUDIO_ENG_DEFAULT, AUDIO_GER, SUB_GER),
arr(a("eng:eng"), a("eng:ger")), "eng:ger",
Map.ofEntries(on(SUB_GER))
)
);
}
@ParameterizedTest
@MethodSource("attributeConfigMatching")
void findDefaultMatchAndApplyChanges(List<TrackAttributes> tracks, AttributeConfig[] config, String expectedConfig, Map<TrackAttributes, Boolean> changes) {
InputConfig.getInstance().setPreferredSubtitles(new HashSet<>());
InputConfig.getInstance().setCommentaryKeywords(new HashSet<>());
InputConfig.getInstance().setForcedKeywords(new HashSet<>());
FileInfo fileInfo = new FileInfo(null);
fileInfo.addTracks(tracks);
AttributeProcessor.findDefaultMatchAndApplyChanges(fileInfo, config);
assertEquals(Strings.isBlank(expectedConfig), fileInfo.getMatchedConfig() == null);
assertEquals(expectedConfig, fileInfo.getMatchedConfig().toStringShort());
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 AttributeConfig[] arr(AttributeConfig... configs) {
return configs;
}
private static AttributeConfig a(String config) {
String[] split = config.split(":");
return new AttributeConfig(split[0], split[1]);
}
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() {
return Stream.of(
);
}
@ParameterizedTest
@MethodSource("filterForPossibleDefaults")
void filterForPossibleDefaults(List<TrackAttributes> tracks, Set<TrackAttributes> expected) {
}
private static Stream<Arguments> findForcedTracksAndApplyChanges() {
return Stream.of(
Arguments.of(List.of(withName(SUB_GER, "song & signs"), withName(SUB_GER, null)),
Set.of("song & signs"), false,
Map.ofEntries(on(withName(SUB_GER, "song & signs")))
),
Arguments.of(List.of(withName(SUB_GER, "song & signs")),
Set.of("song & signs"), false,
Map.ofEntries(on(withName(SUB_GER, "song & signs")))
),
Arguments.of(List.of(withName(SUB_GER_FORCED, "song & signs")),
Set.of("song & signs"), false,
Map.ofEntries()
),
Arguments.of(List.of(SUB_GER_FORCED, withName(SUB_GER, "song & signs")),
Set.of("song & signs"), true,
Map.ofEntries(off(SUB_GER_FORCED), on(withName(SUB_GER, "song & signs")))
)
);
}
@ParameterizedTest
@MethodSource("findForcedTracksAndApplyChanges")
void findForcedTracksAndApplyChanges(List<TrackAttributes> tracks, Set<String> keywords, boolean overwrite, Map<TrackAttributes, Boolean> changes) {
InputConfig.getInstance().setPreferredSubtitles(new HashSet<>());
InputConfig.getInstance().setCommentaryKeywords(new HashSet<>());
InputConfig.getInstance().setHearingImpaired(new HashSet<>());
InputConfig.getInstance().setForcedKeywords(keywords);
InputConfig.getInstance().setOverwriteForced(overwrite);
FileInfo fileInfo = new FileInfo(null);
fileInfo.addTracks(tracks);
AttributeProcessor.findForcedTracksAndApplyChanges(fileInfo);
assertEquals(changes.size(), fileInfo.getChanges().getForcedTrack().size());
changes.forEach((key, value) -> {
assertTrue(fileInfo.getChanges().getForcedTrack().containsKey(key));
assertEquals(value, fileInfo.getChanges().getForcedTrack().get(key));
});
}
private static Stream<Arguments> findCommentaryTracksAndApplyChanges() {
return Stream.of(
Arguments.of(List.of(withName(SUB_GER, "commentary"), withName(SUB_GER, null)),
Set.of("commentary"),
Map.ofEntries(on(withName(SUB_GER, "commentary")))
),
Arguments.of(List.of(withName(SUB_GER, "commentary")),
Set.of("commentary"),
Map.ofEntries(on(withName(SUB_GER, "commentary")))
),
Arguments.of(List.of(withName(AUDIO_GER_COMMENTARY, "commentary")),
Set.of("commentary"),
Map.ofEntries()
),
Arguments.of(List.of(AUDIO_GER_COMMENTARY, withName(SUB_GER, "commentary")),
Set.of("commentary"),
Map.ofEntries(on(withName(SUB_GER, "commentary")))
)
);
}
@ParameterizedTest
@MethodSource("findCommentaryTracksAndApplyChanges")
void findCommentaryTracksAndApplyChanges(List<TrackAttributes> tracks, Set<String> keywords, Map<TrackAttributes, Boolean> changes) {
InputConfig.getInstance().setPreferredSubtitles(new HashSet<>());
InputConfig.getInstance().setCommentaryKeywords(keywords);
InputConfig.getInstance().setHearingImpaired(new HashSet<>());
InputConfig.getInstance().setForcedKeywords(new HashSet<>());
FileInfo fileInfo = new FileInfo(null);
fileInfo.addTracks(tracks);
AttributeProcessor.findCommentaryTracksAndApplyChanges(fileInfo);
assertEquals(changes.size(), fileInfo.getChanges().getCommentaryTrack().size());
changes.forEach((key, value) -> {
assertTrue(fileInfo.getChanges().getCommentaryTrack().containsKey(key));
assertEquals(value, fileInfo.getChanges().getCommentaryTrack().get(key));
});
}
private static Stream<Arguments> findHearingImpairedTracksAndApplyChanges() {
return Stream.of(
Arguments.of(List.of(withName(SUB_GER, "SDH"), withName(SUB_GER, null)),
Set.of("SDH"),
Map.ofEntries(on(withName(SUB_GER, "SDH")))
),
Arguments.of(List.of(withName(SUB_GER, "SDH")),
Set.of("SDH"),
Map.ofEntries(on(withName(SUB_GER, "SDH")))
),
Arguments.of(List.of(withName(AUDIO_GER_COMMENTARY, "SDH")),
Set.of("SDH"),
Map.ofEntries()
),
Arguments.of(List.of(AUDIO_GER_HEARING, withName(SUB_GER, "SDH")),
Set.of("SDH"),
Map.ofEntries(on(withName(SUB_GER, "SDH")))
)
);
}
@ParameterizedTest
@MethodSource("findCommentaryTracksAndApplyChanges")
void findHearingImpairedTracksAndApplyChanges(List<TrackAttributes> tracks, Set<String> keywords, Map<TrackAttributes, Boolean> changes) {
InputConfig.getInstance().setPreferredSubtitles(new HashSet<>());
InputConfig.getInstance().setCommentaryKeywords(new HashSet<>());
InputConfig.getInstance().setHearingImpaired(keywords);
InputConfig.getInstance().setForcedKeywords(new HashSet<>());
FileInfo fileInfo = new FileInfo(null);
fileInfo.addTracks(tracks);
AttributeProcessor.findHearingImpairedTracksAndApplyChanges(fileInfo);
assertEquals(changes.size(), fileInfo.getChanges().getHearingImpairedTrack().size());
changes.forEach((key, value) -> {
assertTrue(fileInfo.getChanges().getHearingImpairedTrack().containsKey(key));
assertEquals(value, fileInfo.getChanges().getHearingImpairedTrack().get(key));
});
}
}

View File

@@ -4,6 +4,7 @@ import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.MethodSource;
import java.nio.file.attribute.FileAttribute;
import java.util.Set; import java.util.Set;
import java.util.stream.Stream; import java.util.stream.Stream;
@@ -14,67 +15,11 @@ import static org.junit.jupiter.api.Assertions.*;
class FileInfoTest { class FileInfoTest {
private static Stream<Arguments> isAudioDifferent() {
return Stream.of(
Arguments.of(createFileInfoAudio(Set.of(AUDIO_GER_DEFAULT), AUDIO_GER_DEFAULT, new AttributeConfig("ger", "")), false),
Arguments.of(createFileInfoAudio(Set.of(AUDIO_GER_DEFAULT), AUDIO_ENG, new AttributeConfig("eng", "")), true),
Arguments.of(createFileInfoAudio(Set.of(AUDIO_GER_DEFAULT, AUDIO_ENG_DEFAULT), AUDIO_GER_DEFAULT, new AttributeConfig("ger", "")), true),
Arguments.of(createFileInfoAudio(Set.of(), AUDIO_GER, new AttributeConfig("ger", "")), true),
Arguments.of(createFileInfoAudio(null, AUDIO_GER, new AttributeConfig("ger", "")), true),
Arguments.of(createFileInfoAudio(Set.of(AUDIO_GER_DEFAULT), null, new AttributeConfig("OFF", "")), true),
Arguments.of(createFileInfoAudio(Set.of(), null, new AttributeConfig("OFF", "")), false),
Arguments.of(createFileInfoAudio(null, null, new AttributeConfig("OFF", "")), false)
);
}
@ParameterizedTest
@MethodSource
void isAudioDifferent(FileInfo underTest, boolean expected) {
assertEquals(expected, underTest.isAudioDifferent());
}
private static Stream<Arguments> isSubtitleDifferent() {
return Stream.of(
Arguments.of(createFileInfoSubs(Set.of(SUB_GER_DEFAULT), SUB_GER_DEFAULT, new AttributeConfig("", "ger")), false),
Arguments.of(createFileInfoSubs(Set.of(SUB_GER_DEFAULT), SUB_ENG, new AttributeConfig("", "eng")), true),
Arguments.of(createFileInfoSubs(Set.of(SUB_GER_DEFAULT, SUB_ENG_DEFAULT), SUB_ENG, new AttributeConfig("", "eng")), true),
Arguments.of(createFileInfoSubs(Set.of(), SUB_ENG, new AttributeConfig("", "ger")), true),
Arguments.of(createFileInfoSubs(null, SUB_GER, new AttributeConfig("", "ger")), true),
Arguments.of(createFileInfoSubs(null, null, new AttributeConfig("", "OFF")), false),
Arguments.of(createFileInfoSubs(Set.of(), null, new AttributeConfig("", "OFF")), false),
Arguments.of(createFileInfoSubs(Set.of(SUB_GER_DEFAULT), null, new AttributeConfig("", "OFF")), true)
);
}
@ParameterizedTest
@MethodSource
void isSubtitleDifferent(FileInfo underTest, boolean expected) {
assertEquals(expected, underTest.isSubtitleDifferent());
}
private static Stream<Arguments> getStatus() { private static Stream<Arguments> getStatus() {
return Stream.of( return Stream.of(
Arguments.of(CHANGE_NECESSARY, createFileInfo(Set.of(AUDIO_GER_DEFAULT), AUDIO_ENG, Set.of(), null, Set.of(), Set.of(), Set.of(), new AttributeConfig("eng", "OFF"))), Arguments.of(CHANGE_NECESSARY, info(new AttributeConfig("ger", "ger"), AUDIO_GER)),
Arguments.of(CHANGE_NECESSARY, createFileInfo(Set.of(), null, Set.of(SUB_GER_DEFAULT), SUB_ENG, Set.of(), Set.of(), Set.of(), new AttributeConfig("OFF", "eng"))), Arguments.of(ALREADY_SUITED, info(new AttributeConfig("ger", "ger"), null)),
Arguments.of(CHANGE_NECESSARY, createFileInfo(Set.of(AUDIO_GER_DEFAULT), AUDIO_ENG, Set.of(SUB_GER_DEFAULT), SUB_ENG, Set.of(), Set.of(), Set.of(), new AttributeConfig("OFF", "eng"))), Arguments.of(NO_SUITABLE_CONFIG, info(null, null))
Arguments.of(CHANGE_NECESSARY, createFileInfo(Set.of(AUDIO_GER_DEFAULT), AUDIO_GER_DEFAULT, Set.of(SUB_GER_DEFAULT), SUB_GER_DEFAULT, Set.of(AUDIO_ENG_FORCED), Set.of(), Set.of(), new AttributeConfig("ger", "ger"))),
Arguments.of(CHANGE_NECESSARY, createFileInfo(Set.of(), null, Set.of(), null, Set.of(AUDIO_ENG_FORCED), Set.of(), Set.of(), new AttributeConfig("OFF", "OFF"))),
Arguments.of(CHANGE_NECESSARY, createFileInfo(Set.of(), null, Set.of(), null, Set.of(), Set.of(), Set.of(SUB_GER_FORCED), new AttributeConfig("OFF", "OFF"))),
Arguments.of(CHANGE_NECESSARY, createFileInfo(Set.of(), null, Set.of(), null, Set.of(), Set.of(SUB_ENG_FORCED), Set.of(SUB_GER_FORCED), new AttributeConfig("OFF", "OFF"))),
Arguments.of(CHANGE_NECESSARY, createFileInfo(Set.of(), null, Set.of(), null, Set.of(AUDIO_ENG_FORCED), Set.of(SUB_ENG_FORCED), Set.of(SUB_GER_FORCED), new AttributeConfig("OFF", "OFF"))),
Arguments.of(CHANGE_NECESSARY, createFileInfo(Set.of(AUDIO_GER_DEFAULT), AUDIO_ENG, Set.of(SUB_GER_DEFAULT), SUB_ENG, Set.of(AUDIO_ENG_FORCED), Set.of(SUB_ENG_FORCED), Set.of(SUB_GER_FORCED), new AttributeConfig("eng", "eng"))),
Arguments.of(CHANGE_NECESSARY, createFileInfo(Set.of(AUDIO_GER_DEFAULT), AUDIO_GER_DEFAULT, Set.of(SUB_GER_DEFAULT), SUB_GER_DEFAULT, Set.of(), Set.of(SUB_ENG_FORCED), Set.of(SUB_ENG_FORCED, SUB_GER), new AttributeConfig("ger", "ger"))),
Arguments.of(NO_SUITABLE_CONFIG, createFileInfo(Set.of(AUDIO_ENG_DEFAULT), null, Set.of(SUB_GER_DEFAULT), null, Set.of(), Set.of(), Set.of(), new AttributeConfig("eng", "ger"))),
Arguments.of(NO_SUITABLE_CONFIG, createFileInfo(Set.of(AUDIO_ENG_DEFAULT), null, Set.of(), null, Set.of(), Set.of(), Set.of(), new AttributeConfig("eng", "ger"))),
Arguments.of(NO_SUITABLE_CONFIG, createFileInfo(Set.of(), null, Set.of(), null, Set.of(), Set.of(), Set.of(), new AttributeConfig("eng", "ger"))),
Arguments.of(ALREADY_SUITED, createFileInfo(Set.of(), null, Set.of(), null, Set.of(), Set.of(), Set.of(), new AttributeConfig("OFF", "OFF"))),
Arguments.of(ALREADY_SUITED, createFileInfo(Set.of(AUDIO_GER_DEFAULT), AUDIO_GER_DEFAULT, Set.of(), null, Set.of(), Set.of(), Set.of(), new AttributeConfig("ger", "OFF"))),
Arguments.of(ALREADY_SUITED, createFileInfo(Set.of(), null, Set.of(SUB_ENG_DEFAULT), SUB_ENG_DEFAULT, Set.of(), Set.of(), Set.of(), new AttributeConfig("OFF", "ger"))),
Arguments.of(ALREADY_SUITED, createFileInfo(Set.of(AUDIO_GER_DEFAULT), AUDIO_GER_DEFAULT, Set.of(SUB_ENG_DEFAULT), SUB_ENG_DEFAULT, Set.of(), Set.of(), Set.of(), new AttributeConfig("ger", "eng"))),
Arguments.of(ALREADY_SUITED, createFileInfo(Set.of(AUDIO_GER_DEFAULT), AUDIO_GER_DEFAULT, Set.of(SUB_ENG_DEFAULT), SUB_ENG_DEFAULT, Set.of(), Set.of(SUB_GER_FORCED), Set.of(SUB_GER_FORCED), new AttributeConfig("ger", "eng")))
); );
} }
@@ -84,4 +29,11 @@ class FileInfoTest {
FileStatus actual = underTest.getStatus(); FileStatus actual = underTest.getStatus();
assertEquals(expected, actual); assertEquals(expected, actual);
} }
private static FileInfo info(AttributeConfig config, TrackAttributes attr) {
FileInfo fileInfo = new FileInfo(null);
fileInfo.setMatchedConfig(config);
if(attr != null) fileInfo.getChanges().getDefaultTrack().put(attr, true);
return fileInfo;
}
} }

View File

@@ -1,8 +1,7 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.config; package at.pcgamingfreaks.mkvaudiosubtitlechanger.model;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.Main; import at.pcgamingfreaks.mkvaudiosubtitlechanger.Main;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validation.ValidationExecutionStrategy; import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.validation.ValidationExecutionStrategy;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.AttributeConfig;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
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;

View File

@@ -1,22 +1,28 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.util; package at.pcgamingfreaks.mkvaudiosubtitlechanger.util;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.FileAttribute; import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.TrackAttributes;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.LaneType; import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.TrackType;
public class FileInfoTestUtil { public class FileInfoTestUtil {
public static final FileAttribute AUDIO_GER_DEFAULT = new FileAttribute(0, "ger", "", true, false, LaneType.AUDIO); public static final TrackAttributes AUDIO_GER_DEFAULT = new TrackAttributes(0, "ger", "", true, false, false, false, TrackType.AUDIO);
public static final FileAttribute AUDIO_ENG_DEFAULT = new FileAttribute(1, "eng", "", true, false, LaneType.AUDIO); public static final TrackAttributes AUDIO_ENG_DEFAULT = new TrackAttributes(1, "eng", "", true, false, false, false, TrackType.AUDIO);
public static final FileAttribute AUDIO_GER = new FileAttribute(0, "ger", "", false, false, LaneType.AUDIO); public static final TrackAttributes AUDIO_GER = new TrackAttributes(0, "ger", "", false, false, false, false, TrackType.AUDIO);
public static final FileAttribute AUDIO_ENG = new FileAttribute(1, "eng", "", false, false, LaneType.AUDIO); public static final TrackAttributes AUDIO_ENG = new TrackAttributes(1, "eng", "", false, false, false, false, TrackType.AUDIO);
public static final FileAttribute AUDIO_GER_FORCED = new FileAttribute(0, "ger", "", false, true, LaneType.AUDIO); public static final TrackAttributes AUDIO_GER_FORCED = new TrackAttributes(0, "ger", "", false, true, false, false, TrackType.AUDIO);
public static final FileAttribute AUDIO_ENG_FORCED = new FileAttribute(1, "eng", "", false, true, LaneType.AUDIO); public static final TrackAttributes AUDIO_ENG_FORCED = new TrackAttributes(1, "eng", "", false, true, false, false, TrackType.AUDIO);
public static final FileAttribute AUDIO_GER_COMMENTARY = new FileAttribute(1, "ger", "commentary", false, false, LaneType.AUDIO); public static final TrackAttributes AUDIO_GER_COMMENTARY = new TrackAttributes(0, "ger", "", false, false, true, false, TrackType.AUDIO);
public static final FileAttribute AUDIO_ENG_COMMENTARY = new FileAttribute(1, "eng", "commentary", false, false, LaneType.AUDIO); public static final TrackAttributes AUDIO_ENG_COMMENTARY = new TrackAttributes(1, "eng", "", false, false, true, false, TrackType.AUDIO);
public static final TrackAttributes AUDIO_GER_HEARING = new TrackAttributes(0, "ger", "", false, false, false, true, TrackType.AUDIO);
public static final TrackAttributes AUDIO_ENG_HEARING = new TrackAttributes(1, "ger", "", false, false, false, true, TrackType.AUDIO);
public static final FileAttribute SUB_GER_DEFAULT = new FileAttribute(0, "ger", "", true, false, LaneType.SUBTITLES); public static final TrackAttributes SUB_GER_DEFAULT = new TrackAttributes(0, "ger", "", true, false, false, false, TrackType.SUBTITLES);
public static final FileAttribute SUB_ENG_DEFAULT = new FileAttribute(1, "eng", "", true, false, LaneType.SUBTITLES); public static final TrackAttributes SUB_ENG_DEFAULT = new TrackAttributes(1, "eng", "", true, false, false, false, TrackType.SUBTITLES);
public static final FileAttribute SUB_GER = new FileAttribute(0, "ger", "", false, false, LaneType.SUBTITLES); public static final TrackAttributes SUB_GER = new TrackAttributes(0, "ger", "", false, false, false, false, TrackType.SUBTITLES);
public static final FileAttribute SUB_ENG = new FileAttribute(1, "eng", "", false, false, LaneType.SUBTITLES); public static final TrackAttributes SUB_ENG = new TrackAttributes(1, "eng", "", false, false, false, false, TrackType.SUBTITLES);
public static final FileAttribute SUB_GER_FORCED = new FileAttribute(0, "ger", "", false, true, LaneType.SUBTITLES); public static final TrackAttributes SUB_GER_FORCED = new TrackAttributes(0, "ger", "", false, true, false, false, TrackType.SUBTITLES);
public static final FileAttribute SUB_ENG_FORCED = new FileAttribute(1, "eng", "", false, true, LaneType.SUBTITLES); public static final TrackAttributes SUB_ENG_FORCED = new TrackAttributes(1, "eng", "", false, true, false, false, TrackType.SUBTITLES);
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());
}
} }

View File

@@ -1,46 +1,7 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.util; package at.pcgamingfreaks.mkvaudiosubtitlechanger.util;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.AttributeConfig;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.FileAttribute;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.FileInfo;
import java.util.Set;
public class TestUtil { public class TestUtil {
public static FileInfo createFileInfoAudio(Set<FileAttribute> defaultAudio, FileAttribute desiredAudio, AttributeConfig config) {
FileInfo fileInfo = new FileInfo(null);
fileInfo.setExistingDefaultAudioLanes(defaultAudio);
fileInfo.setDesiredDefaultAudioLane(desiredAudio);
fileInfo.setMatchedConfig(config);
return fileInfo;
}
public static FileInfo createFileInfoSubs(Set<FileAttribute> defaultSubtitle, FileAttribute desiredSubtitle, AttributeConfig config) {
FileInfo fileInfo = new FileInfo(null);
fileInfo.setExistingDefaultSubtitleLanes(defaultSubtitle);
fileInfo.setDesiredDefaultSubtitleLane(desiredSubtitle);
fileInfo.setMatchedConfig(config);
return fileInfo;
}
public static FileInfo createFileInfo(Set<FileAttribute> defaultAudio, FileAttribute desiredAudio,
Set<FileAttribute> defaultSubtitle, FileAttribute desiredSubtitle,
Set<FileAttribute> existingForcedAudioLanes,
Set<FileAttribute> existingForcedSubs, Set<FileAttribute> desiredForcedSubs,
AttributeConfig matchedConfig) {
FileInfo fileInfo = new FileInfo(null);
fileInfo.setExistingDefaultAudioLanes(defaultAudio);
fileInfo.setDesiredDefaultAudioLane(desiredAudio);
fileInfo.setExistingDefaultSubtitleLanes(defaultSubtitle);
fileInfo.setDesiredDefaultSubtitleLane(desiredSubtitle);
fileInfo.setExistingForcedAudioLanes(existingForcedAudioLanes);
fileInfo.setExistingForcedSubtitleLanes(existingForcedSubs);
fileInfo.setDesiredForcedSubtitleLanes(desiredForcedSubs);
fileInfo.setMatchedConfig(matchedConfig);
return fileInfo;
}
public static String[] args(String... args) { public static String[] args(String... args) {
String[] staticArray = new String[]{"-l", "/", "-a", "jpn:ger"}; String[] staticArray = new String[]{"-l", "/", "-a", "jpn:ger"};
String[] result = new String[staticArray.length + args.length]; String[] result = new String[staticArray.length + args.length];