mirror of
https://github.com/RatzzFatzz/MKVAudioSubtitleChanger.git
synced 2026-02-10 17:55:57 +01:00
Major system rework
This commit is contained in:
53
README.md
53
README.md
@@ -26,31 +26,44 @@ Attribute-config must be entered in pairs: `audio:subtitle`; Example: `jpn:eng`.
|
||||
|
||||
### Available parameters
|
||||
```
|
||||
-a, --attribute-config=<attributeConfig>...
|
||||
List of audio:subtitle pairs used to match in order and update files accordingly (e.g. jpn:eng jpn:ger)
|
||||
-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
|
||||
--commentary-keywords=<commentaryKeywords>[, <commentaryKeywords>...]...
|
||||
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>
|
||||
* -a, --attribute-config=<attributeConfig>...
|
||||
List of audio:subtitle pairs used to match in order
|
||||
and update files accordingly (e.g. jpn:eng jpn:
|
||||
ger)
|
||||
* -l, --library=<libraryPath>
|
||||
path to library
|
||||
-m, --mkvtoolnix=<mkvToolNix>
|
||||
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)
|
||||
-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.
|
||||
```
|
||||
If you need more information how each parameter works, check out [this wiki page](https://github.com/RatzzFatzz/MKVAudioSubtitleChanger/wiki/Parameters-v4).
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
package at.pcgamingfreaks.mkvaudiosubtitlechanger;
|
||||
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.InputConfig;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validation.ValidationExecutionStrategy;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.CachedMkvFileProcessor;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.InputConfig;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.validation.ValidationExecutionStrategy;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.processors.CachedMkvFileProcessor;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.kernel.AttributeUpdaterKernel;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.kernel.CoherentAttributeUpdaterKernel;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.kernel.DefaultAttributeUpdaterKernel;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.MkvFileCollector;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.util.ProjectUtil;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -53,8 +52,8 @@ public class Main implements Runnable {
|
||||
|
||||
InputConfig.setInstance(config);
|
||||
AttributeUpdaterKernel kernel = InputConfig.getInstance().getCoherent() != null
|
||||
? new CoherentAttributeUpdaterKernel(new MkvFileCollector(), new CachedMkvFileProcessor())
|
||||
: new DefaultAttributeUpdaterKernel(new MkvFileCollector(), new CachedMkvFileProcessor());
|
||||
? new CoherentAttributeUpdaterKernel(new CachedMkvFileProcessor())
|
||||
: new DefaultAttributeUpdaterKernel(new CachedMkvFileProcessor());
|
||||
kernel.execute();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -1,33 +1,45 @@
|
||||
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 lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@Slf4j
|
||||
public class FileFilter {
|
||||
static boolean accept(File pathName, String[] fileExtensions) {
|
||||
if (hasProperFileExtension(pathName, fileExtensions)
|
||||
&& hasMatchingPattern(pathName)
|
||||
&& isNewer(pathName)) {
|
||||
return true;
|
||||
private static final String EXTENSION_GROUP = "extension";
|
||||
private static final Pattern extensionPattern = Pattern.compile(String.format(".*(?<%s>\\..*)", EXTENSION_GROUP));
|
||||
|
||||
public static boolean accept(File pathName, Set<String> fileExtensions) {
|
||||
// Ignore files irrelevant for statistics
|
||||
if (!hasProperFileExtension(pathName, new HashSet<>(fileExtensions))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ResultStatistic.getInstance().total();
|
||||
ResultStatistic.getInstance().excluded();
|
||||
return false;
|
||||
if (!hasMatchingPattern(pathName)
|
||||
|| !isNewer(pathName)
|
||||
|| isExcluded(pathName, new HashSet<>(InputConfig.getInstance().getExcluded()))) {
|
||||
ResultStatistic.getInstance().excluded();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean hasProperFileExtension(File pathName, String[] fileExtensions) {
|
||||
return StringUtils.endsWithAny(pathName.getAbsolutePath().toLowerCase(), fileExtensions);
|
||||
private static boolean hasProperFileExtension(File pathName, Set<String> fileExtensions) {
|
||||
Matcher matcher = extensionPattern.matcher(pathName.getName());
|
||||
return matcher.find() && fileExtensions.contains(matcher.group(EXTENSION_GROUP));
|
||||
}
|
||||
|
||||
private static boolean hasMatchingPattern(File pathName) {
|
||||
@@ -49,4 +61,15 @@ public class FileFilter {
|
||||
private static boolean isNewer(Date creationDate) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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<>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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(" "));
|
||||
}
|
||||
}
|
||||
@@ -1,20 +1,20 @@
|
||||
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl;
|
||||
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.FileAttribute;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.TrackAttributes;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class SubtitleTrackComparator implements Comparator<FileAttribute> {
|
||||
public class SubtitleTrackComparator implements Comparator<TrackAttributes> {
|
||||
private final String[] preferredSubtitles;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int compare(FileAttribute track1, FileAttribute track2) {
|
||||
public int compare(TrackAttributes track1, TrackAttributes track2) {
|
||||
int result = 0;
|
||||
|
||||
if (StringUtils.containsAnyIgnoreCase(track1.trackName(), preferredSubtitles)) {
|
||||
@@ -25,8 +25,8 @@ public class SubtitleTrackComparator implements Comparator<FileAttribute> {
|
||||
}
|
||||
|
||||
if (result == 0) {
|
||||
if (track1.defaultTrack()) result++;
|
||||
if (track2.defaultTrack()) result--;
|
||||
if (track1.defaultt()) result++;
|
||||
if (track2.defaultt()) result--;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.converter;
|
||||
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.converter;
|
||||
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.AttributeConfig;
|
||||
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);
|
||||
|
||||
return validateResult(new AttributeConfig(matcher.group("audio"), matcher.group("sub")));
|
||||
return validateResult(new AttributeConfig(matcher.group(AUDIO_GROUP), matcher.group(SUB_GROUP)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1,13 +1,9 @@
|
||||
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.kernel;
|
||||
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.InputConfig;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.exceptions.MkvToolNixException;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.FileCollector;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.FileProcessor;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.AttributeConfig;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.FileAttribute;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.FileInfo;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ResultStatistic;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.processors.AttributeProcessor;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.processors.FileProcessor;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.*;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.util.DateUtils;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.util.ProjectUtil;
|
||||
import at.pcgamingfreaks.yaml.YAML;
|
||||
@@ -23,19 +19,16 @@ import net.harawata.appdirs.AppDirsFactory;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public abstract class AttributeUpdaterKernel {
|
||||
|
||||
protected final FileCollector collector;
|
||||
protected final FileProcessor processor;
|
||||
protected final ResultStatistic statistic = ResultStatistic.getInstance();
|
||||
private final ExecutorService executor = Executors.newFixedThreadPool(InputConfig.getInstance().getThreads());
|
||||
@@ -52,8 +45,10 @@ public abstract class AttributeUpdaterKernel {
|
||||
statistic.startTimer();
|
||||
|
||||
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.refresh();
|
||||
|
||||
files.forEach(file -> executor.submit(() -> {
|
||||
process(file);
|
||||
@@ -64,31 +59,12 @@ public abstract class AttributeUpdaterKernel {
|
||||
executor.awaitTermination(1, TimeUnit.DAYS);
|
||||
}
|
||||
|
||||
endProcess();
|
||||
writeLastExecutionDate();
|
||||
|
||||
statistic.stopTimer();
|
||||
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.
|
||||
* 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
|
||||
*/
|
||||
void process(File file) {
|
||||
FileInfo fileInfo = new FileInfo(file);
|
||||
List<FileAttribute> attributes = processor.loadAttributes(file);
|
||||
FileInfo fileInfo = processor.readAttributes(file);
|
||||
|
||||
if (attributes == null || attributes.isEmpty()) {
|
||||
if (fileInfo.getTracks().isEmpty()) {
|
||||
log.warn("No attributes found for file {}", file);
|
||||
statistic.total();
|
||||
statistic.failure();
|
||||
return;
|
||||
}
|
||||
|
||||
List<FileAttribute> nonForcedTracks = processor.retrieveNonForcedTracks(attributes);
|
||||
List<FileAttribute> nonCommentaryTracks = processor.retrieveNonCommentaryTracks(attributes);
|
||||
AttributeProcessor.findDefaultMatchAndApplyChanges(fileInfo);
|
||||
AttributeProcessor.findForcedTracksAndApplyChanges(fileInfo);
|
||||
AttributeProcessor.findCommentaryTracksAndApplyChanges(fileInfo);
|
||||
AttributeProcessor.findHearingImpairedTracksAndApplyChanges(fileInfo);
|
||||
|
||||
processor.detectDefaultTracks(fileInfo, attributes, nonForcedTracks);
|
||||
processor.detectDesiredTracks(fileInfo, nonForcedTracks, nonCommentaryTracks,
|
||||
InputConfig.getInstance().getAttributeConfig().toArray(new AttributeConfig[]{}));
|
||||
|
||||
updateFile(fileInfo);
|
||||
checkStatusAndUpdate(fileInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -121,8 +93,7 @@ public abstract class AttributeUpdaterKernel {
|
||||
*
|
||||
* @param fileInfo contains information about file and desired configuration.
|
||||
*/
|
||||
protected void updateFile(FileInfo fileInfo) {
|
||||
statistic.total();
|
||||
protected void checkStatusAndUpdate(FileInfo fileInfo) {
|
||||
switch (fileInfo.getStatus()) {
|
||||
case CHANGE_NECESSARY:
|
||||
statistic.shouldChange();
|
||||
@@ -142,12 +113,10 @@ public abstract class AttributeUpdaterKernel {
|
||||
}
|
||||
|
||||
private void commitChange(FileInfo fileInfo) {
|
||||
if (InputConfig.getInstance().isSafeMode()) {
|
||||
return;
|
||||
}
|
||||
if (InputConfig.getInstance().isSafeMode()) return;
|
||||
|
||||
try {
|
||||
processor.update(fileInfo.getFile(), fileInfo);
|
||||
processor.update(fileInfo);
|
||||
statistic.success();
|
||||
log.info("Commited {} to '{}'", fileInfo.getMatchedConfig().toStringShort(), fileInfo.getFile().getAbsolutePath());
|
||||
} 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()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.kernel;
|
||||
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.InputConfig;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.FileCollector;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.FileProcessor;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.InputConfig;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.processors.FileProcessor;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.AttributeConfig;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.FileAttribute;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.FileInfo;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.tongfei.progressbar.ProgressBarBuilder;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
@@ -17,8 +14,8 @@ import java.util.stream.Collectors;
|
||||
@Slf4j
|
||||
public class CoherentAttributeUpdaterKernel extends AttributeUpdaterKernel {
|
||||
|
||||
public CoherentAttributeUpdaterKernel(FileCollector collector, FileProcessor processor) {
|
||||
super(collector, processor);
|
||||
public CoherentAttributeUpdaterKernel(FileProcessor processor) {
|
||||
super(processor);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -27,18 +24,10 @@ public class CoherentAttributeUpdaterKernel extends AttributeUpdaterKernel {
|
||||
.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> excludedFiles = loadExcludedFiles();
|
||||
List<File> directories = collector.loadDirectories(path, depth)
|
||||
.stream().filter(file -> !excludedFiles.contains(file))
|
||||
List<File> directories = processor.loadDirectories(path, depth)
|
||||
.stream()
|
||||
// .filter(file -> !excludedFiles.contains(file))
|
||||
.collect(Collectors.toList());
|
||||
return directories.stream()
|
||||
.filter(dir -> isParentDirectory(dir, directories))
|
||||
@@ -67,43 +56,43 @@ public class CoherentAttributeUpdaterKernel extends AttributeUpdaterKernel {
|
||||
void process(File file, int depth) {
|
||||
// TODO: Implement level crawl if coherence is not possible on user entered depth
|
||||
// IMPL idea: recursive method call, cache needs to be implemented
|
||||
List<FileInfo> fileInfos = collector.loadFiles(file.getAbsolutePath()).stream()
|
||||
.map(FileInfo::new)
|
||||
.collect(Collectors.toList());
|
||||
// List<FileInfoOld> fileInfoOlds = collector.loadFiles(file.getAbsolutePath()).stream()
|
||||
// .map(FileInfoOld::new)
|
||||
// .collect(Collectors.toList());
|
||||
|
||||
for (AttributeConfig config : InputConfig.getInstance().getAttributeConfig()) {
|
||||
|
||||
for (FileInfo fileInfo : fileInfos) {
|
||||
List<FileAttribute> attributes = processor.loadAttributes(fileInfo.getFile());
|
||||
// for (FileInfoOld fileInfoOld : fileInfoOlds) {
|
||||
// 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);
|
||||
List<FileAttribute> nonCommentaryTracks = processor.retrieveNonCommentaryTracks(attributes);
|
||||
|
||||
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);
|
||||
});
|
||||
// fileInfoOlds.forEach(f -> {
|
||||
// f.setDesiredDefaultAudioLane(null);
|
||||
// f.setDesiredDefaultSubtitleLane(null);
|
||||
// });
|
||||
}
|
||||
|
||||
log.info("No coherent match found for {}", file.getAbsoluteFile());
|
||||
|
||||
for (FileInfo fileInfo : fileInfos) {
|
||||
if (!InputConfig.getInstance().isForceCoherent()) {
|
||||
super.process(fileInfo.getFile());
|
||||
} else {
|
||||
statistic.excluded();
|
||||
}
|
||||
}
|
||||
// for (FileInfoOld fileInfoOld : fileInfoOlds) {
|
||||
// if (!InputConfig.getInstance().isForceCoherent()) {
|
||||
// super.process(fileInfoOld.getFile());
|
||||
// } else {
|
||||
// statistic.excluded();
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.kernel;
|
||||
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.InputConfig;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.FileCollector;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.FileProcessor;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.InputConfig;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.processors.FileProcessor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.tongfei.progressbar.ProgressBarBuilder;
|
||||
|
||||
@@ -13,8 +12,8 @@ import java.util.stream.Collectors;
|
||||
@Slf4j
|
||||
public class DefaultAttributeUpdaterKernel extends AttributeUpdaterKernel {
|
||||
|
||||
public DefaultAttributeUpdaterKernel(FileCollector collector, FileProcessor processor) {
|
||||
super(collector, processor);
|
||||
public DefaultAttributeUpdaterKernel(FileProcessor processor) {
|
||||
super(processor);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -22,15 +21,4 @@ public class DefaultAttributeUpdaterKernel extends AttributeUpdaterKernel {
|
||||
return super.pbBuilder()
|
||||
.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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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(" "));
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validation;
|
||||
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.validation;
|
||||
|
||||
import jakarta.validation.Constraint;
|
||||
import jakarta.validation.Payload;
|
||||
@@ -1,4 +1,4 @@
|
||||
package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validation;
|
||||
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.validation;
|
||||
|
||||
import jakarta.validation.ConstraintValidator;
|
||||
import jakarta.validation.ConstraintValidatorContext;
|
||||
@@ -1,4 +1,4 @@
|
||||
package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validation;
|
||||
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.validation;
|
||||
|
||||
import jakarta.validation.Constraint;
|
||||
import jakarta.validation.Payload;
|
||||
@@ -1,4 +1,4 @@
|
||||
package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validation;
|
||||
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.validation;
|
||||
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.MkvToolNix;
|
||||
import jakarta.validation.ConstraintValidator;
|
||||
@@ -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.config.InputConfig;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.InputConfig;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.util.ValidationUtil;
|
||||
import jakarta.validation.ConstraintViolation;
|
||||
import jakarta.validation.Validator;
|
||||
@@ -12,8 +12,8 @@ import java.util.Set;
|
||||
public class ValidationExecutionStrategy implements CommandLine.IExecutionStrategy {
|
||||
|
||||
public int execute(CommandLine.ParseResult parseResult) {
|
||||
validate(parseResult.commandSpec());
|
||||
return new CommandLine.RunLast().execute(parseResult); // default execution strategy
|
||||
if (!parseResult.isVersionHelpRequested() && !parseResult.isUsageHelpRequested()) validate(parseResult.commandSpec());
|
||||
return new CommandLine.RunLast().execute(parseResult);
|
||||
}
|
||||
|
||||
private static void validate(CommandLine.Model.CommandSpec spec) {
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -5,80 +5,38 @@ import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@RequiredArgsConstructor
|
||||
public class FileInfo {
|
||||
private final File file;
|
||||
|
||||
private Set<FileAttribute> existingDefaultAudioLanes = new HashSet<>();
|
||||
private Set<FileAttribute> existingForcedAudioLanes = new HashSet<>();
|
||||
private final List<TrackAttributes> tracks = new ArrayList<>();
|
||||
|
||||
private Set<FileAttribute> existingDefaultSubtitleLanes = new HashSet<>();
|
||||
private Set<FileAttribute> existingForcedSubtitleLanes = new HashSet<>();
|
||||
private final List<TrackAttributes> audioTracks = new ArrayList<>();
|
||||
private final List<TrackAttributes> subtitleTracks = new ArrayList<>();
|
||||
|
||||
private Set<FileAttribute> desiredForcedSubtitleLanes = new HashSet<>();
|
||||
private FileAttribute desiredDefaultAudioLane;
|
||||
private FileAttribute desiredDefaultSubtitleLane;
|
||||
private final PlannedChange changes = new PlannedChange();
|
||||
@Setter
|
||||
private AttributeConfig matchedConfig;
|
||||
|
||||
public boolean isAudioDifferent() {
|
||||
return isMatchDifferent(existingDefaultAudioLanes, desiredDefaultAudioLane)
|
||||
|| isLaneOff(existingDefaultAudioLanes, desiredDefaultAudioLane, AttributeConfig::getAudioLanguage);
|
||||
public void addTrack(TrackAttributes track) {
|
||||
tracks.add(track);
|
||||
if (TrackType.AUDIO.equals(track.type())) audioTracks.add(track);
|
||||
else if (TrackType.SUBTITLES.equals(track.type())) subtitleTracks.add(track);
|
||||
}
|
||||
|
||||
public boolean isSubtitleDifferent() {
|
||||
return isMatchDifferent(existingDefaultSubtitleLanes, desiredDefaultSubtitleLane)
|
||||
|| 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 void addTracks(Collection<TrackAttributes> tracks) {
|
||||
for (TrackAttributes track : tracks) addTrack(track);
|
||||
}
|
||||
|
||||
public FileStatus getStatus() {
|
||||
if (isChangeNecessary()) return FileStatus.CHANGE_NECESSARY;
|
||||
if (isUnableToApplyConfig()) return FileStatus.NO_SUITABLE_CONFIG;
|
||||
if (isAlreadySuited()) return FileStatus.ALREADY_SUITED;
|
||||
if (!changes.isEmpty()) return FileStatus.CHANGE_NECESSARY;
|
||||
if (matchedConfig == null) return FileStatus.NO_SUITABLE_CONFIG;
|
||||
if (changes.isEmpty()) return FileStatus.ALREADY_SUITED;
|
||||
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 +
|
||||
']';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.config.validation.ValidFile;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validation.ValidMkvToolNix;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.AttributeConfig;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.MkvToolNix;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.converter.AttributeConfigConverter;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.validation.ValidFile;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.validation.ValidMkvToolNix;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.util.FileUtils;
|
||||
import jakarta.validation.constraints.Min;
|
||||
import lombok.AccessLevel;
|
||||
@@ -38,18 +36,16 @@ public class InputConfig {
|
||||
@Option(names = {"-a", "--attribute-config"}, required = true, arity = "1..*", converter = AttributeConfigConverter.class,
|
||||
description = "List of audio:subtitle pairs used to match in order and update files accordingly (e.g. jpn:eng jpn:ger)")
|
||||
private List<AttributeConfig> attributeConfig;
|
||||
|
||||
@ValidFile(message = "does not exist")
|
||||
@Option(names = {"-l", "--library"}, required = true, description = "path to library")
|
||||
private File libraryPath;
|
||||
|
||||
@Option(names = {"-s", "--safemode"}, description = "test run (no files will be changes)")
|
||||
private boolean safeMode;
|
||||
|
||||
@ValidMkvToolNix(message = "does not exist")
|
||||
@Option(names = {"-m", "--mkvtoolnix"}, defaultValue = "${DEFAULT_MKV_TOOL_NIX}", description = "path to mkvtoolnix installation")
|
||||
private File mkvToolNix;
|
||||
|
||||
@Option(names = {"-s", "--safemode"}, description = "test run (no files will be changes)")
|
||||
private boolean safeMode;
|
||||
|
||||
@Min(1)
|
||||
@Option(names = {"-t", "--threads"}, defaultValue = "2", description = "thread count (default: ${DEFAULT-VALUE})")
|
||||
private int threads;
|
||||
@@ -57,35 +53,34 @@ public class InputConfig {
|
||||
@Min(0)
|
||||
@Option(names = {"-c", "--coherent"}, description = "try to match all files in dir of depth with the same attribute config")
|
||||
private Integer coherent;
|
||||
|
||||
@Option(names = {"-cf", "--force-coherent"}, description = "changes are only applied if it's a coherent match")
|
||||
private boolean forceCoherent;
|
||||
|
||||
@Option(names = {"-n", "--only-new-file"}, description = "sets filter-date to last successful execution (overwrites input of filter-date)")
|
||||
private boolean onlyNewFiles;
|
||||
|
||||
@Option(names = {"-d", "--filter-date"}, defaultValue = Option.NULL_VALUE, description = "only consider files created newer than entered date (format: \"dd.MM.yyyy-HH:mm:ss\")")
|
||||
private Date filterDate;
|
||||
|
||||
@Option(names = {"-i", "--include-pattern"}, defaultValue = ".*", description = "include files matching pattern (default: \".*\")")
|
||||
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 = ", ",
|
||||
description = "Keywords to identify forced tracks (Defaults will be overwritten; Default: ${DEFAULT-VALUE})")
|
||||
private Set<String> forcedKeywords;
|
||||
|
||||
@Option(names = {"--commentary-keywords"}, arity = "1..*", defaultValue = "commentary, director", split = ", ",
|
||||
@Option(names = {"--commentary-keywords"}, arity = "1..*", defaultValue = "comment, commentary, director", split = ", ",
|
||||
description = "Keywords to identify commentary tracks (Defaults will be overwritten; Default: ${DEFAULT-VALUE})")
|
||||
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 = ", ",
|
||||
description = "Keywords to prefer specific subtitle tracks (Defaults will be overwritten; Default: ${DEFAULT-VALUE})")
|
||||
private Set<String> preferredSubtitles;
|
||||
|
||||
@Option(names = {"--debug"}, description = "Enable debug logging")
|
||||
private boolean debug;
|
||||
|
||||
@@ -136,7 +131,7 @@ public class InputConfig {
|
||||
.add("filterDate=" + filterDate)
|
||||
.add("forcedKeywords=" + forcedKeywords)
|
||||
.add("commentaryKeywords=" + commentaryKeywords)
|
||||
.add("excludedDirectories=" + excludedDirectories)
|
||||
.add("excludedDirectories=" + excluded)
|
||||
.add("preferredSubtitles=" + preferredSubtitles)
|
||||
.add("attributeConfig=" + attributeConfig)
|
||||
.toString();
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@ public class ResultStatistic {
|
||||
"└─ Failed: %s%n" +
|
||||
"Runtime: %s";
|
||||
private static ResultStatistic instance;
|
||||
private int filesTotal = 0;
|
||||
private int total = 0;
|
||||
private int excluded = 0;
|
||||
|
||||
private int shouldChange = 0;
|
||||
@@ -33,18 +33,22 @@ public class ResultStatistic {
|
||||
private long runtime = 0;
|
||||
|
||||
public static ResultStatistic getInstance() {
|
||||
if (instance == null) {
|
||||
return getInstance(false);
|
||||
}
|
||||
|
||||
public static ResultStatistic getInstance(boolean reset) {
|
||||
if (instance == null || reset) {
|
||||
instance = new ResultStatistic();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public void increaseTotalBy(int amount) {
|
||||
filesTotal += amount;
|
||||
total += amount;
|
||||
}
|
||||
|
||||
public synchronized void total() {
|
||||
filesTotal++;
|
||||
total++;
|
||||
}
|
||||
|
||||
public void increaseExcludedBy(int amount) {
|
||||
@@ -110,13 +114,13 @@ public class ResultStatistic {
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ResultStatistic: " + "filesTotal=" + filesTotal +
|
||||
return "ResultStatistic: " + "total=" + total +
|
||||
", excluded=" + excluded +
|
||||
", shouldChange=" + shouldChange +
|
||||
" (failedChanging=" + failedChanging +
|
||||
|
||||
@@ -5,16 +5,17 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import java.util.Objects;
|
||||
|
||||
@Slf4j
|
||||
public record FileAttribute(int id, String language, String trackName, boolean defaultTrack, boolean forcedTrack,
|
||||
LaneType type) {
|
||||
public record TrackAttributes(int id, String language, String trackName,
|
||||
boolean defaultt, boolean forced, boolean commentary, boolean hearingImpaired,
|
||||
TrackType type) {
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
FileAttribute attribute = (FileAttribute) o;
|
||||
TrackAttributes attribute = (TrackAttributes) o;
|
||||
return id == attribute.id
|
||||
&& defaultTrack == attribute.defaultTrack
|
||||
&& forcedTrack == attribute.forcedTrack
|
||||
&& defaultt == attribute.defaultt
|
||||
&& forced == attribute.forced
|
||||
&& Objects.equals(language, attribute.language)
|
||||
&& Objects.equals(trackName, attribute.trackName)
|
||||
&& type == attribute.type;
|
||||
@@ -25,8 +26,8 @@ public record FileAttribute(int id, String language, String trackName, boolean d
|
||||
return "[" + "id=" + id +
|
||||
", language='" + language + '\'' +
|
||||
", trackName='" + trackName + '\'' +
|
||||
", defaultTrack=" + defaultTrack +
|
||||
", forcedTrack=" + forcedTrack +
|
||||
", defaultt=" + defaultt +
|
||||
", forced=" + forced +
|
||||
", type=" + type +
|
||||
']';
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
package at.pcgamingfreaks.mkvaudiosubtitlechanger.model;
|
||||
|
||||
public enum LaneType {
|
||||
public enum TrackType {
|
||||
AUDIO,
|
||||
SUBTITLES;
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.converter;
|
||||
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.converter.AttributeConfigConverter;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.AttributeConfig;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.fields;
|
||||
|
||||
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.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.fields;
|
||||
|
||||
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.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import picocli.CommandLine;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.fields;
|
||||
|
||||
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.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.fields;
|
||||
|
||||
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.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.fields;
|
||||
|
||||
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.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.fields;
|
||||
|
||||
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.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
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 org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
@@ -16,7 +17,9 @@ import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@@ -34,38 +37,44 @@ class FileFilterTest {
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
|
||||
ResultStatistic.getInstance(true);
|
||||
}
|
||||
|
||||
private static Stream<Arguments> accept() {
|
||||
return Stream.of(
|
||||
Arguments.of("~/video.mkv", new String[]{".mkv"}, null, null, ".*", true),
|
||||
Arguments.of("~/video.mp4", new String[]{".mkv"}, null, null, ".*", false),
|
||||
Arguments.of("~/video.mkv", Set.of(".mkv"), -1, ".*", true, 1, 0),
|
||||
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", new String[]{".mkv"}, null, null, "a.*", false),
|
||||
Arguments.of("~/video.mkv", Set.of(".mkv"), -1, "v.*", true, 1, 0),
|
||||
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", new String[]{".mkv"}, new Date(), new Date(System.currentTimeMillis() - 1000), ".*", true)
|
||||
Arguments.of("~/video.mkv", Set.of(".mkv"), -1000, ".*", true, 1, 0),
|
||||
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
|
||||
@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.getName()).thenReturn(List.of(path.split("/")).get(1));
|
||||
when(file.toPath()).thenReturn(Path.of(TEST_FILE));
|
||||
|
||||
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)) {
|
||||
mockedFiles
|
||||
.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");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,11 @@
|
||||
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl;
|
||||
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.InputConfig;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.AttributeConfig;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.FileAttribute;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.processors.MkvFileProcessor;
|
||||
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.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
@@ -29,11 +31,12 @@ class MkvFileProcessorTest {
|
||||
|
||||
@ParameterizedTest
|
||||
@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());
|
||||
FileInfo info = new FileInfo(null);
|
||||
MkvFileProcessor processor = new MkvFileProcessor();
|
||||
processor.detectDesiredTracks(info, tracks, tracks, configs);
|
||||
// processor.detectDesiredTracks(info, tracks, tracks, configs);
|
||||
assertEquals(expectedMatch.getAudioLanguage(), info.getMatchedConfig().getAudioLanguage());
|
||||
assertEquals(expectedMatch.getSubtitleLanguage(), info.getMatchedConfig().getSubtitleLanguage());
|
||||
}
|
||||
@@ -48,43 +51,4 @@ class MkvFileProcessorTest {
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl;
|
||||
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.FileAttribute;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.LaneType;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.TrackAttributes;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.TrackType;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
@@ -34,13 +34,13 @@ class SubtitleTrackComparatorTest {
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("compareArguments")
|
||||
void compare(List<FileAttribute> input, List<FileAttribute> expected) {
|
||||
List<FileAttribute> result = input.stream().sorted(comparator.reversed()).collect(Collectors.toList());
|
||||
void compare(List<TrackAttributes> input, List<TrackAttributes> expected) {
|
||||
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) {
|
||||
return new FileAttribute(0, "", trackName, defaultTrack, false, LaneType.SUBTITLES);
|
||||
private static TrackAttributes attr(String trackName, boolean defaultTrack) {
|
||||
return new TrackAttributes(0, "", trackName, defaultTrack, false, false, false, TrackType.SUBTITLES);
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import java.nio.file.attribute.FileAttribute;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@@ -14,67 +15,11 @@ import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
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() {
|
||||
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, createFileInfo(Set.of(), null, Set.of(SUB_GER_DEFAULT), SUB_ENG, Set.of(), Set.of(), Set.of(), new AttributeConfig("OFF", "eng"))),
|
||||
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(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")))
|
||||
Arguments.of(CHANGE_NECESSARY, info(new AttributeConfig("ger", "ger"), AUDIO_GER)),
|
||||
Arguments.of(ALREADY_SUITED, info(new AttributeConfig("ger", "ger"), null)),
|
||||
Arguments.of(NO_SUITABLE_CONFIG, info(null, null))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -84,4 +29,11 @@ class FileInfoTest {
|
||||
FileStatus actual = underTest.getStatus();
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
package at.pcgamingfreaks.mkvaudiosubtitlechanger.config;
|
||||
package at.pcgamingfreaks.mkvaudiosubtitlechanger.model;
|
||||
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.Main;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validation.ValidationExecutionStrategy;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.AttributeConfig;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.validation.ValidationExecutionStrategy;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
@@ -1,22 +1,28 @@
|
||||
package at.pcgamingfreaks.mkvaudiosubtitlechanger.util;
|
||||
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.FileAttribute;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.LaneType;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.TrackAttributes;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.TrackType;
|
||||
|
||||
public class FileInfoTestUtil {
|
||||
public static final FileAttribute AUDIO_GER_DEFAULT = new FileAttribute(0, "ger", "", true, false, LaneType.AUDIO);
|
||||
public static final FileAttribute AUDIO_ENG_DEFAULT = new FileAttribute(1, "eng", "", true, false, LaneType.AUDIO);
|
||||
public static final FileAttribute AUDIO_GER = new FileAttribute(0, "ger", "", false, false, LaneType.AUDIO);
|
||||
public static final FileAttribute AUDIO_ENG = new FileAttribute(1, "eng", "", false, false, LaneType.AUDIO);
|
||||
public static final FileAttribute AUDIO_GER_FORCED = new FileAttribute(0, "ger", "", false, true, LaneType.AUDIO);
|
||||
public static final FileAttribute AUDIO_ENG_FORCED = new FileAttribute(1, "eng", "", false, true, LaneType.AUDIO);
|
||||
public static final FileAttribute AUDIO_GER_COMMENTARY = new FileAttribute(1, "ger", "commentary", false, false, LaneType.AUDIO);
|
||||
public static final FileAttribute AUDIO_ENG_COMMENTARY = new FileAttribute(1, "eng", "commentary", false, false, LaneType.AUDIO);
|
||||
public static final TrackAttributes AUDIO_GER_DEFAULT = new TrackAttributes(0, "ger", "", true, false, false, false, TrackType.AUDIO);
|
||||
public static final TrackAttributes AUDIO_ENG_DEFAULT = new TrackAttributes(1, "eng", "", true, false, false, false, TrackType.AUDIO);
|
||||
public static final TrackAttributes AUDIO_GER = new TrackAttributes(0, "ger", "", false, false, false, false, TrackType.AUDIO);
|
||||
public static final TrackAttributes AUDIO_ENG = new TrackAttributes(1, "eng", "", false, false, false, false, TrackType.AUDIO);
|
||||
public static final TrackAttributes AUDIO_GER_FORCED = new TrackAttributes(0, "ger", "", false, true, false, false, TrackType.AUDIO);
|
||||
public static final TrackAttributes AUDIO_ENG_FORCED = new TrackAttributes(1, "eng", "", false, true, false, false, TrackType.AUDIO);
|
||||
public static final TrackAttributes AUDIO_GER_COMMENTARY = new TrackAttributes(0, "ger", "", false, false, true, false, TrackType.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 FileAttribute SUB_ENG_DEFAULT = new FileAttribute(1, "eng", "", true, false, LaneType.SUBTITLES);
|
||||
public static final FileAttribute SUB_GER = new FileAttribute(0, "ger", "", false, false, LaneType.SUBTITLES);
|
||||
public static final FileAttribute SUB_ENG = new FileAttribute(1, "eng", "", false, false, LaneType.SUBTITLES);
|
||||
public static final FileAttribute SUB_GER_FORCED = new FileAttribute(0, "ger", "", false, true, LaneType.SUBTITLES);
|
||||
public static final FileAttribute SUB_ENG_FORCED = new FileAttribute(1, "eng", "", false, true, LaneType.SUBTITLES);
|
||||
public static final TrackAttributes SUB_GER_DEFAULT = new TrackAttributes(0, "ger", "", true, false, false, false, TrackType.SUBTITLES);
|
||||
public static final TrackAttributes SUB_ENG_DEFAULT = new TrackAttributes(1, "eng", "", true, false, false, false, TrackType.SUBTITLES);
|
||||
public static final TrackAttributes SUB_GER = new TrackAttributes(0, "ger", "", false, false, false, false, TrackType.SUBTITLES);
|
||||
public static final TrackAttributes SUB_ENG = new TrackAttributes(1, "eng", "", false, false, false, false, TrackType.SUBTITLES);
|
||||
public static final TrackAttributes SUB_GER_FORCED = new TrackAttributes(0, "ger", "", false, true, false, false, TrackType.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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,46 +1,7 @@
|
||||
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 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) {
|
||||
String[] staticArray = new String[]{"-l", "/", "-a", "jpn:ger"};
|
||||
String[] result = new String[staticArray.length + args.length];
|
||||
|
||||
Reference in New Issue
Block a user