Change track selection

This commit is contained in:
2022-03-28 22:35:02 +02:00
parent 68e5b9e988
commit c11431d85b
15 changed files with 266 additions and 136 deletions

View File

@@ -149,6 +149,11 @@
<artifactId>commons-cli</artifactId>
<version>1.5.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
<!-- endregion -->
<!-- region unit-tests -->
<dependency>

View File

@@ -1,10 +1,12 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.FileCollector;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.FileProcessor;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.AttributeConfig;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.intimpl.ConfigProcessor;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.intimpl.MkvFileCollector;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.ConfigProcessorOld;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.FileAttribute;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.Config;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.FileInfoDto;
import lombok.SneakyThrows;
import lombok.extern.log4j.Log4j2;
@@ -16,19 +18,30 @@ import java.util.concurrent.*;
public class AttributeUpdaterKernel {
ExecutorService executor = Executors.newFixedThreadPool(Config.getInstance().getThreadCount());
MkvFileCollector collector = new MkvFileCollector();
FileCollector collector;
FileProcessor processor;
int filesChangedAmount = 0;
int filesNotChangedAmount = 0;
long runtime = 0;
public AttributeUpdaterKernel(FileCollector collector, FileProcessor processor) {
this.collector = collector;
this.processor = processor;
}
@SneakyThrows
public void execute() {
long beforeTimer = System.currentTimeMillis();
collector.loadFiles(Config.getInstance().getLibraryPath())
.forEach(file -> executor.submit(() -> process(file)));
List<File> files = collector.loadFiles(Config.getInstance().getLibraryPath());
files.forEach(file -> executor.submit(() -> process(file)));
executor.shutdown();
executor.awaitTermination(1, TimeUnit.DAYS);
runtime = System.currentTimeMillis() - beforeTimer;
System.out.printf("%nFiles %schanged: %s%n",
@@ -40,13 +53,13 @@ public class AttributeUpdaterKernel {
System.out.printf("Runtime: %ss%n", runtime / 1000);
}
private void process(File file) {
List<FileAttribute> attributes = collector.loadAttributes(file);
private void processOld(File file) {
List<FileAttribute> attributes = processor.loadAttributes(file);
boolean fileHasChanged = false;
if (attributes.isEmpty()) return;
for(AttributeConfig config : Config.getInstance().getAttributeConfig()){
fileHasChanged = new ConfigProcessor(config).processConfig(file, attributes);
fileHasChanged = new ConfigProcessorOld(config).processConfig(file, attributes);
if(fileHasChanged) break;
}
if(!fileHasChanged){
@@ -57,4 +70,12 @@ public class AttributeUpdaterKernel {
}
System.out.print(".");
}
private void process(File file) {
List<FileAttribute> attributes = processor.loadAttributes(file);
FileInfoDto fileInfo = processor.filterAttributes(attributes);
if (fileInfo.isChangeNecessary() && !Config.getInstance().isSafeMode()) {
processor.update(file, fileInfo);
}
}
}

View File

@@ -1,6 +1,8 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.Config;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.MkvFileCollector;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.MkvFileProcessor;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.cli.*;
@@ -10,7 +12,7 @@ import static java.lang.Integer.parseInt;
public class Main {
public static void main(String[] args) {
initConfig(args);
AttributeUpdaterKernel kernel = new AttributeUpdaterKernel();
AttributeUpdaterKernel kernel = new AttributeUpdaterKernel(new MkvFileCollector(), new MkvFileProcessor());
kernel.execute();
}

View File

@@ -1,4 +1,4 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.intimpl;
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.Config;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.AttributeConfig;
@@ -17,12 +17,12 @@ import java.util.List;
import static java.lang.String.format;
@Log4j2
public class ConfigProcessor {
public class ConfigProcessorOld {
private int audioDefault = - 1;
private int subtitleDefault = - 1;
private final AttributeConfig config;
public ConfigProcessor(AttributeConfig config) {
public ConfigProcessorOld(AttributeConfig config) {
this.config = config;
}
@@ -59,22 +59,22 @@ public class ConfigProcessor {
if(elem.isDefaultTrack()){
audioDefault = elem.getId();
}
if(config.getAudio().contains("OFF")){
if(config.getAudioLanguage().contains("OFF")){
transfer.setAudioOn(false);
transfer.setAudioIndex(- 2);
}
if(! config.getAudio().contains(elem.getLanguage())){
if(! config.getAudioLanguage().contains(elem.getLanguage())){
iterator.remove();
}
}else if("subtitles".equals(elem.getType())){
if(elem.isDefaultTrack()){
subtitleDefault = elem.getId();
}
if(config.getSubtitle().contains("OFF")){
if(config.getSubtitleLanguage().contains("OFF")){
transfer.setSubtitleOn(false);
transfer.setSubtitleIndex(- 2);
}
if(! config.getSubtitle().contains(elem.getLanguage())){
if(! config.getSubtitleLanguage().contains(elem.getLanguage())){
iterator.remove();
}
}

View File

@@ -0,0 +1,13 @@
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);
}

View File

@@ -0,0 +1,20 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.FileAttribute;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.FileInfoDto;
import java.io.File;
import java.util.List;
public interface FileProcessor {
/**
* @param file Takes the file from which the attributes will be returned
* @return list of all important attributes
*/
List<FileAttribute> loadAttributes(File file);
FileInfoDto filterAttributes(List<FileAttribute> attributes);
void update(File file, FileInfoDto fileInfo);
}

View File

@@ -0,0 +1,40 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl;
import lombok.extern.log4j.Log4j2;
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;
@Log4j2
public class MkvFileCollector implements FileCollector {
@Override
public List<File> loadFiles(String path) {
File file = new File(path);
if (file.isFile() && file.getAbsolutePath().endsWith(".mkv")) {
return new ArrayList<File>() {{
add(file);
}};
} else if (file.isDirectory()) {
try (Stream<Path> paths = Files.walk(Paths.get(path))) {
return paths
.filter(Files::isRegularFile)
.map(Path::toFile)
.filter(f -> f.getAbsolutePath().endsWith(".mkv"))
.collect(Collectors.toList());
} catch (IOException e) {
log.error("Couldn't find file or directory!", e);
return new ArrayList<>();
}
} else {
return new ArrayList<>();
}
}
}

View File

@@ -0,0 +1,100 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.Config;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.*;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.stream.Collectors;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.LaneType.AUDIO;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.LaneType.SUBTITLES;
@Log4j2
public class MkvFileProcessor implements FileProcessor {
private final ObjectMapper mapper = new ObjectMapper();
@Override
public List<FileAttribute> loadAttributes(File file) {
Map<String, Object> jsonMap;
List<FileAttribute> fileAttributes = new ArrayList<>();
try {
String command = String.format("\"%s\"", Config.getInstance().getPathFor(MkvToolNix.MKV_MERGER));
String[] arguments = new String[]{
command,
"--identify",
"--identification-format",
"json",
file.getAbsoluteFile().toString()
};
InputStream inputStream = Runtime.getRuntime().exec(arguments).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.getAbsoluteFile().toString());
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))));
}
}
} catch (IOException e) {
e.printStackTrace();
log.error("File could not be found or loaded!");
}
return fileAttributes;
}
@Override
public FileInfoDto filterAttributes(List<FileAttribute> attributes) {
FileInfoDto info = new FileInfoDto();
for (FileAttribute attribute: attributes) {
if (attribute.isDefaultTrack() && AUDIO.equals(attribute.getType())) info.setDefaultAudioLane(attribute);
if (attribute.isForcedTrack() && AUDIO.equals(attribute.getType())) info.setForcedAudioLane(attribute);
if (attribute.isDefaultTrack() && SUBTITLES.equals(attribute.getType())) info.setDefaultSubtitleLane(attribute);
if (attribute.isForcedTrack() && SUBTITLES.equals(attribute.getType())) info.setForcedSubtitleLane(attribute);
}
List<FileAttribute> nonForcedTracks = attributes.stream()
.filter(elem -> !StringUtils.containsIgnoreCase(elem.getTrackName(), "forced"))
.collect(Collectors.toList());
for (AttributeConfig config: Config.getInstance().getAttributeConfig()) {
FileAttribute desiredAudio = null;
FileAttribute desiredSubtitle = null;
for (FileAttribute attribute: nonForcedTracks) {
if ( attribute.getLanguage().equals(config.getAudioLanguage())
&& AUDIO.equals(attribute.getType())) desiredAudio = attribute;
if ( attribute.getLanguage().equals(config.getSubtitleLanguage())
&& SUBTITLES.equals(attribute.getType())) desiredSubtitle = attribute;
}
if (desiredAudio != null && desiredSubtitle != null) {
info.setDesiredAudioLane(desiredAudio);
info.setDesiredSubtitleLane(desiredSubtitle);
break;
}
}
return info;
}
@Override
public void update(File file, FileInfoDto fileInfo) {
}
}

View File

@@ -1,12 +0,0 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.intimpl;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.FileAttribute;
import java.io.File;
import java.util.List;
public interface FileCollector {
List<File> loadFiles(String path);
List<FileAttribute> loadAttributes(File file);
}

View File

@@ -1,95 +0,0 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.intimpl;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.FileAttribute;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.Config;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.MkvToolNix;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.log4j.Log4j2;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
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.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@Log4j2
public class MkvFileCollector implements FileCollector {
private final ObjectMapper mapper = new ObjectMapper();
/**
* @param path Is entered path, which leads to one file directly or a directory which will be loaded recursive
* @return list of all files within the directory, if it's only a file, the file will be returned in a list
*/
@Override
public List<File> loadFiles(String path) {
File file = new File(path);
if (file.isFile() && file.getAbsolutePath().endsWith(".mkv")) {
return new ArrayList<File>() {{
add(file);
}};
} else if (file.isDirectory()) {
try (Stream<Path> paths = Files.walk(Paths.get(path))) {
return paths
.filter(Files::isRegularFile)
.map(Path::toFile)
.filter(f -> f.getAbsolutePath().endsWith(".mkv"))
.collect(Collectors.toList());
} catch (IOException e) {
log.error("Couldn't find file or directory!", e);
return new ArrayList<>();
}
} else {
return new ArrayList<>();
}
}
/**
* @param file Takes the file from which the attributes will be returned
* @return list of all important attributes
*/
@Override
public List<FileAttribute> loadAttributes(File file) {
Map<String, Object> jsonMap;
List<FileAttribute> fileAttributes = new ArrayList<>();
try {
String command = String.format("\"%s\"", Config.getInstance().getPathFor(MkvToolNix.MKV_MERGER));
String[] array = new String[]{
command,
"--identify",
"--identification-format",
"json",
file.getAbsoluteFile().toString()
};
InputStream inputStream = Runtime.getRuntime().exec(array).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.getAbsoluteFile().toString());
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),
(String) attribute.get("type")));
}
}
} catch (IOException e) {
e.printStackTrace();
log.error("File could not be found or loaded!");
}
return fileAttributes;
}
}

View File

@@ -3,29 +3,26 @@ package at.pcgamingfreaks.mkvaudiosubtitlechanger.model;
import lombok.Getter;
import lombok.extern.log4j.Log4j2;
import java.util.List;
import java.util.stream.Collectors;
@Log4j2
@Getter
public class AttributeConfig {
private String audio;
private String subtitle;
private String audioLanguage;
private String subtitleLanguage;
public AttributeConfig(String audio, String subtitle) {
this.audio = audio;
this.subtitle = subtitle;
public AttributeConfig(String audioLanguage, String subtitleLanguage) {
this.audioLanguage = audioLanguage;
this.subtitleLanguage = subtitleLanguage;
}
public boolean isValid() {
return audio != null && subtitle != null;
return audioLanguage != null && subtitleLanguage != null;
}
@Override
public String toString() {
final StringBuffer sb = new StringBuffer("AttributeConfig{");
sb.append("audio='").append(audio).append('\'');
sb.append(", subtitle='").append(subtitle).append('\'');
sb.append("audioLanguage='").append(audioLanguage).append('\'');
sb.append(", subtitleLanguage='").append(subtitleLanguage).append('\'');
sb.append('}');
return sb.toString();
}

View File

@@ -20,9 +20,10 @@ public class FileAttribute {
private String trackName;
private boolean defaultTrack;
private boolean forcedTrack;
private String type;
private LaneType type;
public FileAttribute(int id, String language, String trackName, boolean defaultTrack, boolean forcedTrack, String type) {
public FileAttribute(int id, String language, String trackName, boolean defaultTrack, boolean forcedTrack,
LaneType type) {
this.id = id;
this.language = language;
this.trackName = trackName;

View File

@@ -0,0 +1,20 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.model;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class FileInfoDto {
private FileAttribute defaultAudioLane;
private FileAttribute defaultSubtitleLane;
private FileAttribute forcedAudioLane;
private FileAttribute forcedSubtitleLane;
private FileAttribute desiredAudioLane;
private FileAttribute desiredSubtitleLane;
public boolean isChangeNecessary() {
return defaultAudioLane.getId() != desiredAudioLane.getId()
|| defaultSubtitleLane.getId() != desiredSubtitleLane.getId();
}
}

View File

@@ -0,0 +1,14 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.model;
public enum LaneType {
AUDIO,
SUBTITLES;
LaneType() {
}
@Override
public String toString() {
return name();
}
}

View File

@@ -0,0 +1,4 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.model;
public class ResultStatistic {
}