mirror of
https://github.com/RatzzFatzz/MKVAudioSubtitleChanger.git
synced 2026-02-11 02:05:56 +01:00
Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5d86b43388 | |||
| d637558cfe | |||
| 4e53d99c25 | |||
|
|
a19fbac03a | ||
| a5b0224d6c | |||
| f7a2e4234a | |||
| 93f3542cf1 | |||
|
|
b94f6eb7de | ||
| c11431d85b | |||
| 68e5b9e988 | |||
| a1e9031cbc | |||
| 1df06e8a08 | |||
| feaeda746a | |||
| f2fb296698 | |||
| 03efab657c | |||
| bba612476b | |||
|
|
097499a916 | ||
|
|
3617d84b3e | ||
|
|
ecbfc77da0 | ||
|
|
1ed1b6e057 | ||
|
|
013c46d940 | ||
|
|
a41895df1b | ||
|
|
6ba5064ca9 | ||
|
|
9775be153b |
41
README.md
41
README.md
@@ -17,30 +17,33 @@ This program helps changing audio and subtitle lines of mkv files.
|
||||
|
||||
Opening terminal / cmd in the directory of the jar and the config file and execute following command:
|
||||
|
||||
`java -jar mkvaudiosubtitleschanger.jar [path to mkv or dir with mkv]`
|
||||
`java -jar mkvaudiosubtitleschanger.jar -l [path to mkv or dir with mkv]`
|
||||
|
||||
You have to replace the brackets and the content of it with the path to your mkv file or the directory with mkv files.
|
||||
### Additional arameters
|
||||
```properties
|
||||
-c,--config path to config
|
||||
-h,--help "for help this is" - Yoda
|
||||
-k,--forcedKeywords <arg> Additional keywords to identify forced tracks
|
||||
-l,--library <arg> path to library (Required)
|
||||
-s,--safe-mode Test run (no files will be changes)
|
||||
-t,--threads <arg> thread count
|
||||
```
|
||||
|
||||
### config.yml example
|
||||
Config file needs to be placed in the same directory as the jar.
|
||||
Config file needs to be placed in the same directory as the jar or path to config has to be passed via command line
|
||||
argument.
|
||||
|
||||
```
|
||||
mkvtoolnixPath: /usr/bin
|
||||
```yaml
|
||||
mkvtoolnixPath: C:\Program Files\MKVToolNix
|
||||
# Recommendations for data stored on HDDs, increase when using SSDs
|
||||
threads: 2
|
||||
#forcedKeywords: ["forced", "signs"]
|
||||
config:
|
||||
1:
|
||||
audio:
|
||||
- jpn
|
||||
subtitle:
|
||||
- ger
|
||||
- eng
|
||||
audio: ger
|
||||
subtitle: OFF
|
||||
2:
|
||||
audio:
|
||||
- ger
|
||||
- eng
|
||||
subtitle:
|
||||
- OFF
|
||||
audio: eng
|
||||
subtitle: ger
|
||||
```
|
||||
This config will first check if there is japanese audio and german or english subtitles available, if yes,
|
||||
it will set these attributes. If these are not available, it will check the second part. This means, it checks
|
||||
if german or english audio is available. It does not care for the subtitle, because it's "off", which means, it
|
||||
will disable subtitles in this case.
|
||||
Subtitle lanes recognized as forced will be set as one. Already existing ones will not be overwritten or changed.
|
||||
|
||||
11
config-template.yaml
Normal file
11
config-template.yaml
Normal file
@@ -0,0 +1,11 @@
|
||||
mkvtoolnixPath: C:\Program Files\MKVToolNix
|
||||
# Recommendations for data stored on HDDs, increase when using SSDs
|
||||
threads: 2
|
||||
#forcedKeywords: ["forced", "signs"]
|
||||
config:
|
||||
1:
|
||||
audio: ger
|
||||
subtitle: OFF
|
||||
2:
|
||||
audio: eng
|
||||
subtitle: ger
|
||||
14
config.yaml
14
config.yaml
@@ -1,14 +0,0 @@
|
||||
mkvtoolnixPath: /usr/bin
|
||||
config:
|
||||
1:
|
||||
audio:
|
||||
- jpn
|
||||
subtitle:
|
||||
- ger
|
||||
- eng
|
||||
2:
|
||||
audio:
|
||||
- ger
|
||||
- eng
|
||||
subtitle:
|
||||
- OFF
|
||||
31
pom.xml
31
pom.xml
@@ -4,9 +4,9 @@
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>MKVAudioSubtilesChanger</groupId>
|
||||
<artifactId>MKVAudioSubtitlesChanger</artifactId>
|
||||
<version>1.0</version>
|
||||
<groupId>MKVAudioSubtileChanger</groupId>
|
||||
<artifactId>MKVAudioSubtitleChanger</artifactId>
|
||||
<version>2.0</version>
|
||||
|
||||
<build>
|
||||
<defaultGoal>clean package</defaultGoal>
|
||||
@@ -106,17 +106,17 @@
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-api</artifactId>
|
||||
<version>2.12.0</version>
|
||||
<version>2.17.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-core</artifactId>
|
||||
<version>2.12.0</version>
|
||||
<version>2.17.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-slf4j-impl</artifactId>
|
||||
<version>2.12.0</version>
|
||||
<version>2.17.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
@@ -137,12 +137,27 @@
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.dataformat</groupId>
|
||||
<artifactId>jackson-dataformat-yaml</artifactId>
|
||||
<version>2.9.9</version>
|
||||
<version>2.13.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>2.9.10.4</version>
|
||||
<version>2.13.2.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-cli</groupId>
|
||||
<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>
|
||||
<dependency>
|
||||
<groupId>me.tongfei</groupId>
|
||||
<artifactId>progressbar</artifactId>
|
||||
<version>0.9.3</version>
|
||||
</dependency>
|
||||
<!-- endregion -->
|
||||
<!-- region unit-tests -->
|
||||
|
||||
@@ -1,42 +1,78 @@
|
||||
package at.pcgamingfreaks.mkvaudiosubtitlechanger;
|
||||
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.AttributeConfig;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ConfigProcessor;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.intimpl.MkvFileCollector;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.Config;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.FileCollector;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.FileProcessor;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.FileAttribute;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.util.ConfigUtil;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.FileInfoDto;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ResultStatistic;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import me.tongfei.progressbar.ProgressBar;
|
||||
import me.tongfei.progressbar.ProgressBarBuilder;
|
||||
import me.tongfei.progressbar.ProgressBarStyle;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Log4j2
|
||||
public class AttributeUpdaterKernel {
|
||||
MkvFileCollector collector = new MkvFileCollector();
|
||||
|
||||
public void execute(String path) {
|
||||
List<AttributeConfig> configPattern = ConfigUtil.loadConfig();
|
||||
List<File> allValidPaths = collector.loadFiles(path);
|
||||
if(allValidPaths != null && configPattern != null){
|
||||
for(File file : allValidPaths){
|
||||
List<FileAttribute> attributes = collector.loadAttributes(file);
|
||||
boolean fileHasChanged = false;
|
||||
for(AttributeConfig config : configPattern){
|
||||
/*
|
||||
* Creating new ArrayList, because the method removes elements from the list by reference
|
||||
*/
|
||||
fileHasChanged = new ConfigProcessor(config).processConfig(file, new ArrayList<>(attributes));
|
||||
if(fileHasChanged){
|
||||
break;
|
||||
private final ExecutorService executor = Executors.newFixedThreadPool(Config.getInstance().getThreadCount());
|
||||
private final FileCollector collector;
|
||||
private final FileProcessor processor;
|
||||
private final ResultStatistic statistic = new ResultStatistic();
|
||||
|
||||
public AttributeUpdaterKernel(FileCollector collector, FileProcessor processor) {
|
||||
this.collector = collector;
|
||||
this.processor = processor;
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public void execute() {
|
||||
statistic.startTimer();
|
||||
|
||||
try (ProgressBar progressBar = pbBuilder().build()) {
|
||||
List<File> files = collector.loadFiles(Config.getInstance().getLibraryPath());
|
||||
progressBar.maxHint(files.size());
|
||||
files.forEach(file -> executor.submit(() -> process(file, progressBar)));
|
||||
executor.shutdown();
|
||||
executor.awaitTermination(1, TimeUnit.DAYS);
|
||||
}
|
||||
if(! fileHasChanged){
|
||||
log.info(file.getName() + " didn't change!");
|
||||
|
||||
statistic.stopTimer();
|
||||
System.out.println(statistic);
|
||||
}
|
||||
|
||||
private void process(File file, ProgressBar progressBar) {
|
||||
statistic.total();
|
||||
List<FileAttribute> attributes = processor.loadAttributes(file);
|
||||
FileInfoDto fileInfo = processor.filterAttributes(attributes);
|
||||
if (fileInfo.isChangeNecessary()) {
|
||||
statistic.shouldChange();
|
||||
if (!Config.getInstance().isSafeMode()) {
|
||||
try {
|
||||
processor.update(file, fileInfo);
|
||||
statistic.success();
|
||||
} catch (IOException e) {
|
||||
statistic.failure();
|
||||
log.warn("File couldn't be updated: {}", file.getAbsoluteFile());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.error("Path is not valid or config has errors!");
|
||||
}
|
||||
statistic.fits();
|
||||
}
|
||||
progressBar.step();
|
||||
}
|
||||
|
||||
private static ProgressBarBuilder pbBuilder() {
|
||||
return new ProgressBarBuilder()
|
||||
.setStyle(ProgressBarStyle.ASCII)
|
||||
.setUpdateIntervalMillis(250)
|
||||
.setMaxRenderedLength(75);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,40 +1,62 @@
|
||||
package at.pcgamingfreaks.mkvaudiosubtitlechanger;
|
||||
|
||||
import at.pcgamingfreaks.yaml.YAML;
|
||||
import at.pcgamingfreaks.yaml.YamlInvalidContentException;
|
||||
import at.pcgamingfreaks.yaml.YamlKeyNotFoundException;
|
||||
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.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty.*;
|
||||
import static java.lang.Integer.parseInt;
|
||||
|
||||
@Log4j2
|
||||
public class Main {
|
||||
public static void main(String[] args) {
|
||||
if(checkIfMKVToolNixIsValid()){
|
||||
AttributeUpdaterKernel kernel = new AttributeUpdaterKernel();
|
||||
kernel.execute(args[0]);
|
||||
}else{
|
||||
log.error("MKVToolNix was not found! Please recheck path");
|
||||
initConfig(args);
|
||||
AttributeUpdaterKernel kernel = new AttributeUpdaterKernel(new MkvFileCollector(), new MkvFileProcessor());
|
||||
kernel.execute();
|
||||
}
|
||||
|
||||
private static void initConfig(String[] args) {
|
||||
Options options = new Options();
|
||||
options.addOption("h", HELP.toString(), false, "\"for help this is\" - Yoda");
|
||||
options.addRequiredOption("l", LIBRARY.toString(), true, "path to library");
|
||||
options.addOption("c", CONFIG.toString(), false, "path to config");
|
||||
options.addOption("t", THREADS.toString(), true, "thread count");
|
||||
options.addOption("s", SAFE_MODE.toString(), false, "Test run (no files will be changes)");
|
||||
options.addOption(create("k", FORCED_KEYWORDS.toString(), Option.UNLIMITED_VALUES, "Additional keywords to identify forced tracks"));
|
||||
|
||||
CommandLineParser parser = new DefaultParser();
|
||||
HelpFormatter formatter = new HelpFormatter();
|
||||
try {
|
||||
CommandLine cmd = parser.parse(options, args);
|
||||
|
||||
if (cmd.hasOption("help")) {
|
||||
formatter.printHelp("java -jar MKVAudioSubtitlesChanger.jar -p <path_to_library>", options);
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
Config config = Config.getInstance();
|
||||
config.loadConfig(cmd.getOptionValue(CONFIG.toString(), "config.yaml")); // use cmd input
|
||||
config.setLibraryPath(cmd.getOptionValue("library"));
|
||||
config.setSafeMode(cmd.hasOption("safe-mode"));
|
||||
if (cmd.hasOption("threads")) config.setThreadCount(parseInt(cmd.getOptionValue("threads")));
|
||||
if (cmd.hasOption(FORCED_KEYWORDS.toString()))
|
||||
config.getForcedKeywords().addAll(List.of(cmd.getOptionValues(FORCED_KEYWORDS.toString())));
|
||||
config.isValid();
|
||||
} catch (ParseException e) {
|
||||
log.error(e);
|
||||
formatter.printHelp("java -jar MKVAudioSubtitlesChanger.jar -p <path_to_library>", options);
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean checkIfMKVToolNixIsValid() {
|
||||
try{
|
||||
String path = new YAML(new File("config.yaml")).getString("mkvtoolnixPath");
|
||||
if(! path.endsWith(File.separator)){
|
||||
path += File.separator;
|
||||
}
|
||||
if(System.getProperty("os.name").toLowerCase().contains("windows")){
|
||||
MKVToolProperties.getInstance().setMkvmergePath(path + "mkvmerge.exe");
|
||||
MKVToolProperties.getInstance().setMkvpropeditPath(path + "mkvpropedit.exe");
|
||||
}else{
|
||||
MKVToolProperties.getInstance().setMkvmergePath(path + "mkvmerge");
|
||||
MKVToolProperties.getInstance().setMkvpropeditPath(path + "mkvpropedit");
|
||||
}
|
||||
}catch(YamlKeyNotFoundException | IOException | YamlInvalidContentException e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
return new File(MKVToolProperties.getInstance().getMkvmergePath()).isFile() && new File(MKVToolProperties.getInstance().getMkvpropeditPath()).isFile();
|
||||
private static Option create(String opt, String longOpt, int args, String desc) {
|
||||
Option option = new Option(opt, desc);
|
||||
option.setLongOpt(longOpt);
|
||||
option.setArgs(args);
|
||||
return option;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
package at.pcgamingfreaks.mkvaudiosubtitlechanger.config;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Log4j2
|
||||
@Getter
|
||||
public class AttributeConfig {
|
||||
private List<String> audio;
|
||||
private List<String> subtitle;
|
||||
|
||||
public AttributeConfig(List<String> audio, List<String> subtitle) {
|
||||
this.audio = audio;
|
||||
this.subtitle = subtitle;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
package at.pcgamingfreaks.mkvaudiosubtitlechanger.config;
|
||||
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.AttributeConfig;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.MkvToolNix;
|
||||
import at.pcgamingfreaks.yaml.YAML;
|
||||
import at.pcgamingfreaks.yaml.YamlInvalidContentException;
|
||||
import at.pcgamingfreaks.yaml.YamlKeyNotFoundException;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty.MKV_TOOL_NIX;
|
||||
|
||||
@Log4j2
|
||||
@Getter
|
||||
@Setter
|
||||
public class Config {
|
||||
@Getter(AccessLevel.NONE)
|
||||
@Setter(AccessLevel.NONE)
|
||||
private static Config config = null;
|
||||
|
||||
private List<AttributeConfig> attributeConfig;
|
||||
private int threadCount;
|
||||
private Set<String> forcedKeywords = new HashSet<>(Arrays.asList("forced", "signs"));
|
||||
@Getter(AccessLevel.NONE)
|
||||
private String mkvtoolnixPath;
|
||||
private String libraryPath;
|
||||
private boolean isSafeMode;
|
||||
private boolean isWindows;
|
||||
|
||||
public static Config getInstance() {
|
||||
if (config == null) {
|
||||
config = new Config();
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
public void isValid() throws RuntimeException {
|
||||
boolean isValid = true;
|
||||
if (attributeConfig == null || attributeConfig.isEmpty()
|
||||
|| !attributeConfig.stream().allMatch(AttributeConfig::isValid)) {
|
||||
isValid = false;
|
||||
System.out.println("Audio & subtitle configuration invalid!");
|
||||
}
|
||||
if (threadCount <= 0) {
|
||||
isValid = false;
|
||||
System.out.println("Thread count needs to be at least 1!");
|
||||
}
|
||||
if (mkvtoolnixPath.isEmpty()
|
||||
|| !new File(getPathFor(MkvToolNix.MKV_MERGER)).isFile()
|
||||
|| !new File(getPathFor(MkvToolNix.MKV_PROP_EDIT)).isFile()) {
|
||||
isValid = false;
|
||||
System.out.println("MkvToolNix installation path invalid!");
|
||||
}
|
||||
|
||||
if (!isValid) {
|
||||
throw new RuntimeException("Invalid configuration");
|
||||
}
|
||||
}
|
||||
|
||||
public void loadConfig(String configPath) {
|
||||
try (YAML config = new YAML(new File(configPath))) {
|
||||
setAttributeConfig(loadAttributeConfig(config));
|
||||
setThreadCount(loadThreadCount(config));
|
||||
setMkvtoolnixPath(loadMkvToolNixPath(config));
|
||||
setWindows(System.getProperty("os.name").toLowerCase().contains("windows"));
|
||||
getForcedKeywords().addAll(loadForcedKeywords(config));
|
||||
} catch (YamlInvalidContentException | YamlKeyNotFoundException | IOException e) {
|
||||
log.fatal("Config could not be loaded: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private List<AttributeConfig> loadAttributeConfig(YAML config) {
|
||||
Function<String, String> audio = key -> config.getString(key + ".audio", null);
|
||||
Function<String, String> subtitle = key -> config.getString(key + ".subtitle", null);
|
||||
|
||||
return config.getKeysFiltered(".*audio.*").stream()
|
||||
.sorted()
|
||||
.map(key -> key.replace(".audio", ""))
|
||||
.map(key -> new AttributeConfig(audio.apply(key), subtitle.apply(key)))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private int loadThreadCount(YAML config) throws YamlKeyNotFoundException {
|
||||
return config.isSet(ConfigProperty.THREADS.toString())
|
||||
? Integer.parseInt(config.getString(ConfigProperty.THREADS.toString()))
|
||||
: 1;
|
||||
}
|
||||
|
||||
private List<String> loadForcedKeywords(YAML config) {
|
||||
return config.getStringList(ConfigProperty.FORCED_KEYWORDS.toString(), new ArrayList<>());
|
||||
}
|
||||
|
||||
private String loadMkvToolNixPath(YAML config) throws YamlKeyNotFoundException {
|
||||
return config.isSet(MKV_TOOL_NIX.toString())
|
||||
? config.getString(MKV_TOOL_NIX.toString())
|
||||
: defaultMkvToolNixPath();
|
||||
}
|
||||
|
||||
private String defaultMkvToolNixPath() {
|
||||
return System.getProperty("os.name").toLowerCase().contains("windows")
|
||||
? "C:/Program Files/MKVToolNix/"
|
||||
: "/usr/bin/";
|
||||
}
|
||||
|
||||
public String getPathFor(MkvToolNix exe) {
|
||||
return mkvtoolnixPath.endsWith("/") ? mkvtoolnixPath + exe : mkvtoolnixPath + "/" + exe;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,194 +0,0 @@
|
||||
package at.pcgamingfreaks.mkvaudiosubtitlechanger.config;
|
||||
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.MKVToolProperties;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.FileAttribute;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
@Log4j2
|
||||
public class ConfigProcessor {
|
||||
private int audioDefault = - 1;
|
||||
private int subtitleDefault = - 1;
|
||||
private final AttributeConfig config;
|
||||
|
||||
public ConfigProcessor(AttributeConfig config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the config lists and apply the changes if the combination matches
|
||||
*
|
||||
* @param file is the file, which will be updated
|
||||
* @param attributes has the metadata for the transferred file
|
||||
* @return If the current configuration matched and changes applied or not
|
||||
*/
|
||||
public boolean processConfig(File file, List<FileAttribute> attributes) {
|
||||
// check if size is bigger or equal 2 to make sure that there is at least one audio and subtitle line
|
||||
// TODO: implement empty audio or subtitle line
|
||||
if(attributes.size() >= 2){
|
||||
TransferObject transfer = filterAttributes(attributes);
|
||||
if(! attributes.isEmpty()){
|
||||
return updateFile(file, attributes, transfer);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Filters the attributes that only those are remaining which are needed in the current configuration.
|
||||
* Also analyzes which tracks were default before.
|
||||
*/
|
||||
private TransferObject filterAttributes(List<FileAttribute> attributes) {
|
||||
TransferObject transfer = new TransferObject();
|
||||
Iterator<FileAttribute> iterator = attributes.iterator();
|
||||
while(iterator.hasNext()){
|
||||
FileAttribute elem = iterator.next();
|
||||
if("audio".equals(elem.getType())){
|
||||
if(elem.isDefaultTrack()){
|
||||
audioDefault = elem.getId();
|
||||
}
|
||||
if(config.getAudio().contains("OFF")){
|
||||
transfer.setAudioOn(false);
|
||||
transfer.setAudioIndex(- 2);
|
||||
}
|
||||
if(! config.getAudio().contains(elem.getLanguage())){
|
||||
iterator.remove();
|
||||
}
|
||||
}else if("subtitles".equals(elem.getType())){
|
||||
if(elem.isDefaultTrack()){
|
||||
subtitleDefault = elem.getId();
|
||||
}
|
||||
if(config.getSubtitle().contains("OFF")){
|
||||
transfer.setSubtitleOn(false);
|
||||
transfer.setSubtitleIndex(- 2);
|
||||
}
|
||||
if(! config.getSubtitle().contains(elem.getLanguage())){
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
return transfer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the command which will be executed if the attributes of the current file fit the current {@link AttributeConfig}
|
||||
*
|
||||
* @param file is the file, which will be updated
|
||||
* @param attributes has the metadata for the transferred file
|
||||
* @return if the the current file was updated or not. Returns true if the file already has the correct metadata set
|
||||
*/
|
||||
private boolean updateFile(File file, List<FileAttribute> attributes, TransferObject transfer) {
|
||||
StringBuilder stringBuffer = new StringBuilder();
|
||||
if(System.getProperty("os.name").toLowerCase().contains("windows")){
|
||||
stringBuffer.append("\"");
|
||||
stringBuffer.append(MKVToolProperties.getInstance().getMkvpropeditPath());
|
||||
stringBuffer.append("\" \"").append(file.getAbsolutePath()).append("\" ");
|
||||
}else{
|
||||
stringBuffer.append(MKVToolProperties.getInstance().getMkvpropeditPath());
|
||||
stringBuffer.append(" ").append(file.getAbsolutePath()).append(" ");
|
||||
}
|
||||
if(audioDefault != - 1){
|
||||
stringBuffer.append("--edit track:=").append(audioDefault).append(" --set flag-default=0 ");
|
||||
}
|
||||
if(subtitleDefault != - 1){
|
||||
stringBuffer.append("--edit track:=").append(subtitleDefault).append(" --set flag-default=0 ");
|
||||
}
|
||||
collectLines(attributes, transfer);
|
||||
if(transfer.isValid){
|
||||
if(transfer.isAudioOn){
|
||||
stringBuffer.append("--edit track:=").append(transfer.getAudioIndex()).append(" --set flag-default=1 ");
|
||||
}
|
||||
if(transfer.isSubtitleOn){
|
||||
stringBuffer.append("--edit track:=").append(transfer.getSubtitleIndex()).append(" --set flag-default=1 ");
|
||||
}
|
||||
if(subtitleDefault == transfer.getSubtitleIndex() && audioDefault == transfer.getAudioIndex()){
|
||||
/*
|
||||
* In this case the file would be change to the exact same audio and subtitle lines and we want to
|
||||
* avoid unnecessary changes to the file
|
||||
*/
|
||||
log.info(file.getName() + " already fits config!");
|
||||
return true;
|
||||
}
|
||||
try{
|
||||
Runtime.getRuntime().exec(stringBuffer.toString());
|
||||
}catch(IOException e){
|
||||
log.error("Couldn't make changes to file");
|
||||
}
|
||||
/*
|
||||
* We return true even if there was an error. If there was an error, the chances that this file is still
|
||||
* busy later.
|
||||
*/
|
||||
log.info(file.getName() + " was updated");
|
||||
return true;
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Analyzes the left over attributes and decides which is the most wanted for audio and subtitle
|
||||
*
|
||||
* @param attributes contains all the leftover attributes
|
||||
* @return is an object, which contains information about which audio and subtitle line is the best suitable for
|
||||
* the entered config. Also transfers a boolean which contains information about if the other two values
|
||||
* were set
|
||||
*/
|
||||
private TransferObject collectLines(List<FileAttribute> attributes, TransferObject transfer) {
|
||||
int subtitleListIndex = - 1;
|
||||
int audioListIndex = - 1;
|
||||
for(FileAttribute elem : attributes){
|
||||
if("audio".equals(elem.getType())){
|
||||
for(int i = 0; i < config.getAudio().size(); i++){
|
||||
audioListIndex = findIndex("audio", elem, audioListIndex, config.getAudio(), transfer);
|
||||
}
|
||||
}else if("subtitles".equals(elem.getType())){
|
||||
for(int i = 0; i < config.getSubtitle().size(); i++){
|
||||
subtitleListIndex = findIndex("subtitles", elem, subtitleListIndex, config.getSubtitle(), transfer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
transfer.analyzeIfValid();
|
||||
return transfer;
|
||||
}
|
||||
|
||||
private int findIndex(String type, FileAttribute elem, int index, List<String> config, TransferObject transfer) {
|
||||
for(int i = 0; i < config.size(); i++){
|
||||
if(config.get(i).equals(elem.getLanguage()) && (index == - 1 || i < index)){
|
||||
switch(type){
|
||||
case "audio":
|
||||
transfer.setAudioIndex(elem.getId());
|
||||
break;
|
||||
case "subtitles":
|
||||
transfer.setSubtitleIndex(elem.getId());
|
||||
break;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private static class TransferObject {
|
||||
private boolean isValid;
|
||||
private int audioIndex = - 1;
|
||||
private int subtitleIndex = - 1;
|
||||
private boolean isSubtitleOn = true;
|
||||
private boolean isAudioOn = true;
|
||||
|
||||
TransferObject() {
|
||||
}
|
||||
|
||||
private void analyzeIfValid() {
|
||||
isValid = audioIndex != - 1 && subtitleIndex != - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl;
|
||||
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.FileAttribute;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.FileInfoDto;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
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) throws IOException;
|
||||
}
|
||||
@@ -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<>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
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 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 static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.LaneType.AUDIO;
|
||||
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.LaneType.SUBTITLES;
|
||||
import static java.lang.String.format;
|
||||
|
||||
@Log4j2
|
||||
public class MkvFileProcessor implements FileProcessor {
|
||||
private final ObjectMapper mapper = new ObjectMapper();
|
||||
private final String[] forcedKeywords = new String[]{"forced", "signs"};
|
||||
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 ENABLE_FORCED_TRACK = "--edit track:%s --set flag-forced=1 ";
|
||||
|
||||
|
||||
@Override
|
||||
public List<FileAttribute> loadAttributes(File file) {
|
||||
Map<String, Object> jsonMap;
|
||||
List<FileAttribute> fileAttributes = new ArrayList<>();
|
||||
try {
|
||||
String command = 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.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))));
|
||||
}
|
||||
}
|
||||
} 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();
|
||||
List<FileAttribute> nonForcedTracks = attributes.stream()
|
||||
.filter(elem -> !StringUtils.containsAnyIgnoreCase(elem.getTrackName(), forcedKeywords))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
detectCurrentConfiguration(attributes, info, nonForcedTracks);
|
||||
detectDesiredConfiguration(info, nonForcedTracks);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
private void detectCurrentConfiguration(List<FileAttribute> attributes, FileInfoDto info, List<FileAttribute> nonForcedTracks) {
|
||||
Set<FileAttribute> detectedForcedSubtitleLanes = new HashSet<>();
|
||||
for (FileAttribute attribute : attributes) {
|
||||
if (attribute.isDefaultTrack() && AUDIO.equals(attribute.getType())) info.setDefaultAudioLane(attribute);
|
||||
if (attribute.isDefaultTrack() && SUBTITLES.equals(attribute.getType()))
|
||||
info.setDefaultSubtitleLane(attribute);
|
||||
if (attribute.isForcedTrack() && SUBTITLES.equals(attribute.getType()))
|
||||
detectedForcedSubtitleLanes.add(attribute);
|
||||
}
|
||||
|
||||
info.setDesiredForcedSubtitleLanes(attributes.stream()
|
||||
.filter(e -> !nonForcedTracks.contains(e))
|
||||
.filter(e -> !detectedForcedSubtitleLanes.contains(e))
|
||||
.collect(Collectors.toSet())
|
||||
);
|
||||
}
|
||||
|
||||
private void detectDesiredConfiguration(FileInfoDto info, List<FileAttribute> nonForcedTracks) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(File file, FileInfoDto fileInfo) throws IOException {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append(format("\"%s\" ", Config.getInstance().getPathFor(MkvToolNix.MKV_PROP_EDIT)));
|
||||
sb.append(format("\"%s\" ", file.getAbsolutePath()));
|
||||
if (fileInfo.isAudioDifferent()) {
|
||||
if (fileInfo.getDefaultAudioLane() != null) {
|
||||
sb.append(format(DISABLE_DEFAULT_TRACK, fileInfo.getDefaultAudioLane().getId()));
|
||||
}
|
||||
sb.append(format(ENABLE_DEFAULT_TRACK, fileInfo.getDesiredAudioLane().getId()));
|
||||
}
|
||||
if (fileInfo.isSubtitleDifferent()) {
|
||||
if (fileInfo.getDefaultSubtitleLane() != null) {
|
||||
sb.append(format(DISABLE_DEFAULT_TRACK, fileInfo.getDefaultSubtitleLane().getId()));
|
||||
}
|
||||
sb.append(format(ENABLE_DEFAULT_TRACK, fileInfo.getDesiredSubtitleLane().getId()));
|
||||
}
|
||||
if (fileInfo.areForcedTracksDifferent()) {
|
||||
for (FileAttribute attribute : fileInfo.getDesiredForcedSubtitleLanes()) {
|
||||
sb.append(format(ENABLE_FORCED_TRACK, attribute.getId()));
|
||||
}
|
||||
}
|
||||
|
||||
InputStream inputstream = Runtime.getRuntime().exec(sb.toString()).getInputStream();
|
||||
log.debug(IOUtils.toString(new InputStreamReader(inputstream)));
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
package at.pcgamingfreaks.mkvaudiosubtitlechanger.intimpl;
|
||||
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.MKVToolProperties;
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.FileAttribute;
|
||||
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 null;
|
||||
}
|
||||
}else{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 = "";
|
||||
if(System.getProperty("os.name").toLowerCase().contains("windows")){
|
||||
command = "\"" + MKVToolProperties.getInstance().getMkvmergePath() + "\"";
|
||||
}else{
|
||||
command = MKVToolProperties.getInstance().getMkvmergePath();
|
||||
}
|
||||
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");
|
||||
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.get("default_track"),
|
||||
(Boolean) properties.get("forced_track"),
|
||||
(String) attribute.get("type")));
|
||||
}
|
||||
}
|
||||
}catch(IOException e){
|
||||
e.printStackTrace();
|
||||
log.error("File could not be found or loaded!");
|
||||
}
|
||||
return fileAttributes;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package at.pcgamingfreaks.mkvaudiosubtitlechanger.model;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
|
||||
@Log4j2
|
||||
@Getter
|
||||
public class AttributeConfig {
|
||||
private final String audioLanguage;
|
||||
private final String subtitleLanguage;
|
||||
|
||||
public AttributeConfig(String audioLanguage, String subtitleLanguage) {
|
||||
this.audioLanguage = audioLanguage;
|
||||
this.subtitleLanguage = subtitleLanguage;
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
return audioLanguage != null && subtitleLanguage != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuffer sb = new StringBuffer("AttributeConfig{");
|
||||
sb.append("audioLanguage='").append(audioLanguage).append('\'');
|
||||
sb.append(", subtitleLanguage='").append(subtitleLanguage).append('\'');
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package at.pcgamingfreaks.mkvaudiosubtitlechanger.model;
|
||||
|
||||
public enum ConfigProperty {
|
||||
MKV_TOOL_NIX("mkvtoolnixPath"),
|
||||
THREADS("threads"),
|
||||
FORCED_KEYWORDS("forcedKeywords"),
|
||||
CONFIG("config"),
|
||||
LIBRARY("library"),
|
||||
SAFE_MODE("safe-mode"),
|
||||
HELP("help");
|
||||
|
||||
private final String property;
|
||||
|
||||
ConfigProperty(String property) {
|
||||
this.property = property;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return property;
|
||||
}
|
||||
}
|
||||
@@ -3,26 +3,17 @@ package at.pcgamingfreaks.mkvaudiosubtitlechanger.model;
|
||||
import lombok.Getter;
|
||||
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.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@Log4j2
|
||||
@Getter
|
||||
public class FileAttribute {
|
||||
private int id;
|
||||
private String language;
|
||||
private String trackName;
|
||||
private boolean defaultTrack;
|
||||
private boolean forcedTrack;
|
||||
private String type;
|
||||
private final int id;
|
||||
private final String language;
|
||||
private final String trackName;
|
||||
private final boolean defaultTrack;
|
||||
private final boolean forcedTrack;
|
||||
private final 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;
|
||||
@@ -30,28 +21,4 @@ public class FileAttribute {
|
||||
this.forcedTrack = forcedTrack;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public static boolean pathIsValid(String path) {
|
||||
File file = new File(path);
|
||||
if(file.isFile()){
|
||||
return file.getAbsolutePath().endsWith(".mkv");
|
||||
}
|
||||
if(file.isDirectory()){
|
||||
try(Stream<Path> paths = Files.walk(Paths.get(path))){
|
||||
List<String> allPaths = paths
|
||||
.filter(Files::isRegularFile)
|
||||
.map(f -> f.toAbsolutePath().toString())
|
||||
.collect(Collectors.toList());
|
||||
for(String filePath : allPaths){
|
||||
if(! filePath.endsWith(".mkv")){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}catch(IOException e){
|
||||
log.error("Couldn't find file or directory!", e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package at.pcgamingfreaks.mkvaudiosubtitlechanger.model;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class FileInfoDto {
|
||||
private FileAttribute defaultAudioLane;
|
||||
private FileAttribute defaultSubtitleLane;
|
||||
private Set<FileAttribute> desiredForcedSubtitleLanes;
|
||||
private FileAttribute desiredAudioLane;
|
||||
private FileAttribute desiredSubtitleLane;
|
||||
|
||||
public boolean isChangeNecessary() {
|
||||
return isAudioDifferent() || isSubtitleDifferent() || areForcedTracksDifferent();
|
||||
}
|
||||
|
||||
public boolean isAudioDifferent() {
|
||||
return desiredAudioLane != null &&
|
||||
(defaultAudioLane == null || defaultAudioLane.getId() != desiredAudioLane.getId());
|
||||
}
|
||||
|
||||
public boolean isSubtitleDifferent() {
|
||||
return desiredSubtitleLane != null &&
|
||||
(defaultSubtitleLane == null || defaultSubtitleLane.getId() != desiredSubtitleLane.getId());
|
||||
}
|
||||
|
||||
public boolean areForcedTracksDifferent() {
|
||||
return desiredForcedSubtitleLanes.size() > 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package at.pcgamingfreaks.mkvaudiosubtitlechanger.model;
|
||||
|
||||
public enum LaneType {
|
||||
AUDIO,
|
||||
SUBTITLES;
|
||||
|
||||
LaneType() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package at.pcgamingfreaks.mkvaudiosubtitlechanger.model;
|
||||
|
||||
public enum MkvToolNix {
|
||||
MKV_MERGER("mkvmerge.exe"),
|
||||
MKV_PROP_EDIT("mkvpropedit.exe");
|
||||
|
||||
private final String file;
|
||||
|
||||
MkvToolNix(String file) {
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return file;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package at.pcgamingfreaks.mkvaudiosubtitlechanger.model;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
@Getter
|
||||
public class ResultStatistic {
|
||||
private static final String result = "Total files: %s%n" +
|
||||
"├─ Should change: %s%n" +
|
||||
"├─ Successfully changed: %s%n" +
|
||||
"├─ Already fit config: %s%n" +
|
||||
"└─ Failed: %s%n" +
|
||||
"Runtime: %ss";
|
||||
|
||||
private int filesTotal = 0;
|
||||
private int filesShouldChange = 0;
|
||||
private int filesSuccessfullyChanged = 0;
|
||||
private int filesFailed = 0;
|
||||
private int filesAlreadyFit = 0;
|
||||
@Getter(AccessLevel.NONE)
|
||||
private long startTime = 0;
|
||||
private long runtime = 0;
|
||||
|
||||
public synchronized void total() {
|
||||
filesTotal++;
|
||||
}
|
||||
|
||||
public synchronized void shouldChange() {
|
||||
filesShouldChange++;
|
||||
}
|
||||
|
||||
public synchronized void success() {
|
||||
filesSuccessfullyChanged++;
|
||||
}
|
||||
|
||||
public synchronized void failure() {
|
||||
filesFailed++;
|
||||
}
|
||||
|
||||
public synchronized void fits() {
|
||||
filesAlreadyFit++;
|
||||
}
|
||||
|
||||
public void startTimer() {
|
||||
startTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public void stopTimer() {
|
||||
runtime = System.currentTimeMillis() - startTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format(result, filesTotal, filesShouldChange, filesSuccessfullyChanged, filesAlreadyFit,
|
||||
filesFailed, runtime / 1000);
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
package at.pcgamingfreaks.mkvaudiosubtitlechanger.util;
|
||||
|
||||
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.AttributeConfig;
|
||||
import at.pcgamingfreaks.yaml.YAML;
|
||||
import at.pcgamingfreaks.yaml.YamlInvalidContentException;
|
||||
import at.pcgamingfreaks.yaml.YamlKeyNotFoundException;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Log4j2
|
||||
public class ConfigUtil {
|
||||
public static List<AttributeConfig> loadConfig() {
|
||||
try(YAML yaml = new YAML(new File("config.yaml"))){
|
||||
return yaml.getKeysFiltered(".*audio.*").stream()
|
||||
.sorted()
|
||||
.map(elem -> elem.replace(".audio", ""))
|
||||
.map(elem -> createAttributeConfig(elem, yaml))
|
||||
.collect(Collectors.toList());
|
||||
}catch(YamlInvalidContentException | IOException e){
|
||||
log.fatal("Config could not be loaded");
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static AttributeConfig createAttributeConfig(String key, YAML yaml) {
|
||||
try{
|
||||
return new AttributeConfig(
|
||||
yaml.getStringList(key + ".audio"),
|
||||
yaml.getStringList(key + ".subtitle"));
|
||||
}catch(YamlKeyNotFoundException e){
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,6 @@
|
||||
Configuration:
|
||||
name: DefaultLogger
|
||||
Appenders:
|
||||
Console:
|
||||
name: Console_Out
|
||||
PatternLayout:
|
||||
Pattern: "%d{DEFAULT} | %-5level | %thread | %msg %n %throwable"
|
||||
ThresholdFilter:
|
||||
level: debug
|
||||
File:
|
||||
name: FileAppender
|
||||
fileName: default.log
|
||||
@@ -18,11 +12,9 @@ Configuration:
|
||||
Root:
|
||||
level: debug
|
||||
AppenderRef:
|
||||
- ref: Console_Out
|
||||
- ref: FileAppender
|
||||
Logger:
|
||||
name: "com.zaxxer.hikari.HikariConfig"
|
||||
level: info
|
||||
AppenderRef:
|
||||
- ref: Console_Out
|
||||
- ref: FileAppender
|
||||
Reference in New Issue
Block a user