Prepare for coherent feature by restructuring AttributeUpdaterKernel

This commit is contained in:
2023-02-26 18:55:17 +01:00
parent 143206b08c
commit 73be93a4b6
18 changed files with 340 additions and 166 deletions

View File

@@ -1,5 +1,6 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.exceptions.MkvToolNixException;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.FileAttribute;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.FileInfoDto;
@@ -10,12 +11,35 @@ 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);
FileInfoDto filterAttributes(List<FileAttribute> attributes);
/**
* 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(FileInfoDto info, List<FileAttribute> attributes, List<FileAttribute> nonForcedTracks);
void update(File file, FileInfoDto fileInfo) throws IOException;
/**
* Populate FileInfoDto with the desired tracks, based on AttributeConfig.
* @param info to be populated
* @param nonForcedTracks List of all not forced tracks
* @param nonCommentaryTracks List of all not commentary tracks
*/
void detectDesiredTracks(FileInfoDto info, List<FileAttribute> nonForcedTracks, List<FileAttribute> nonCommentaryTracks);
/**
* Update the file.
* @param file to be updated
* @param fileInfo information to update file
* @throws IOException
* @throws MkvToolNixException when error occurs while sending query to mkvpropedit
*/
void update(File file, FileInfoDto fileInfo) throws IOException, MkvToolNixException;
}

View File

@@ -1,6 +1,6 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl;
import lombok.extern.log4j.Log4j2;
import lombok.extern.slf4j.Slf4j;
import java.io.File;
import java.io.IOException;
@@ -12,7 +12,7 @@ import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@Log4j2
@Slf4j
public class MkvFileCollector implements FileCollector {
private static final String[] fileExtensions = new String[]{".mkv", ".mka", ".mks", ".mk3d"};

View File

@@ -1,11 +1,11 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.Config;
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.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.core.util.IOUtils;
import java.io.File;
@@ -19,14 +19,13 @@ import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.LaneType.AUDIO;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.LaneType.SUBTITLES;
import static java.lang.String.format;
@Log4j2
@Slf4j
public class MkvFileProcessor implements FileProcessor {
private final ObjectMapper mapper = new ObjectMapper();
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 ";
@SuppressWarnings("unchecked")
@Override
public List<FileAttribute> loadAttributes(File file) {
@@ -62,7 +61,7 @@ public class MkvFileProcessor implements FileProcessor {
}
}
log.debug(fileAttributes);
log.debug(fileAttributes.toString());
} catch (IOException e) {
e.printStackTrace();
log.error("File could not be found or loaded!");
@@ -70,27 +69,11 @@ public class MkvFileProcessor implements FileProcessor {
return fileAttributes;
}
/**
* {@inheritDoc}
*/
@Override
public FileInfoDto filterAttributes(List<FileAttribute> attributes) {
FileInfoDto info = new FileInfoDto();
List<FileAttribute> nonForcedTracks = attributes.stream()
.filter(elem -> !StringUtils.containsAnyIgnoreCase(elem.getTrackName(),
Config.getInstance().getForcedKeywords().toArray(new CharSequence[0])))
.filter(elem -> !elem.isForcedTrack())
.collect(Collectors.toList());
List<FileAttribute> nonCommentaryTracks = attributes.stream()
.filter(elem -> !StringUtils.containsAnyIgnoreCase(elem.getTrackName(),
Config.getInstance().getCommentaryKeywords().toArray(new CharSequence[0])))
.collect(Collectors.toList());
detectDefaultTracks(info, attributes, nonForcedTracks);
detectDesiredTracks(info, nonForcedTracks, nonCommentaryTracks);
log.debug(info);
return info;
}
protected void detectDefaultTracks(FileInfoDto info, List<FileAttribute> attributes, List<FileAttribute> nonForcedTracks) {
public void detectDefaultTracks(FileInfoDto info, List<FileAttribute> attributes, List<FileAttribute> nonForcedTracks) {
Set<FileAttribute> detectedForcedSubtitleLanes = new HashSet<>();
for (FileAttribute attribute : attributes) {
if (attribute.isDefaultTrack() && AUDIO.equals(attribute.getType()))
@@ -108,7 +91,11 @@ public class MkvFileProcessor implements FileProcessor {
);
}
protected void detectDesiredTracks(FileInfoDto info, List<FileAttribute> nonForcedTracks, List<FileAttribute> nonCommentaryTracks) {
/**
* {@inheritDoc}
*/
@Override
public void detectDesiredTracks(FileInfoDto info, List<FileAttribute> nonForcedTracks, List<FileAttribute> nonCommentaryTracks) {
for (AttributeConfig config : Config.getInstance().getAttributeConfig()) {
FileAttribute desiredAudio = null;
FileAttribute desiredSubtitle = null;
@@ -126,11 +113,15 @@ public class MkvFileProcessor implements FileProcessor {
}
}
/**
* {@inheritDoc}
*/
@Override
public void update(File file, FileInfoDto fileInfo) throws IOException, RuntimeException {
public void update(File file, FileInfoDto fileInfo) throws IOException, MkvToolNixException {
StringBuilder sb = new StringBuilder();
sb.append(format("\"%s\" ", Config.getInstance().getPathFor(MkvToolNix.MKV_PROP_EDIT)));
sb.append(format("\"%s\" ", file.getAbsolutePath()));
if (fileInfo.isAudioDifferent()) {
if (fileInfo.getDefaultAudioLanes() != null && !fileInfo.getDefaultSubtitleLanes().isEmpty()) {
for (FileAttribute track: fileInfo.getDefaultAudioLanes()) {
@@ -139,6 +130,7 @@ public class MkvFileProcessor implements FileProcessor {
}
sb.append(format(ENABLE_DEFAULT_TRACK, fileInfo.getDesiredAudioLane().getId()));
}
if (fileInfo.isSubtitleDifferent()) {
if (fileInfo.getDefaultSubtitleLanes() != null && !fileInfo.getDefaultSubtitleLanes().isEmpty()) {
for (FileAttribute track: fileInfo.getDefaultSubtitleLanes()) {
@@ -147,6 +139,7 @@ public class MkvFileProcessor implements FileProcessor {
}
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()));
@@ -156,6 +149,6 @@ public class MkvFileProcessor implements FileProcessor {
InputStream inputstream = Runtime.getRuntime().exec(sb.toString()).getInputStream();
String output = IOUtils.toString(new InputStreamReader(inputstream));
log.debug(output);
if (output.contains("Error")) throw new RuntimeException(output);
if (output.contains("Error")) throw new MkvToolNixException(output);
}
}

View File

@@ -0,0 +1,116 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.kernel;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.Config;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.exceptions.MkvToolNixException;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.FileCollector;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.FileProcessor;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.FileInfoDto;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ResultStatistic;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import me.tongfei.progressbar.ProgressBar;
import me.tongfei.progressbar.ProgressBarBuilder;
import me.tongfei.progressbar.ProgressBarStyle;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
@Slf4j
@RequiredArgsConstructor
public abstract class AttributeUpdaterKernel {
protected final FileCollector collector;
protected final FileProcessor processor;
protected final ResultStatistic statistic = new ResultStatistic();
private final ExecutorService executor = Executors.newFixedThreadPool(Config.getInstance().getThreads());
private static ProgressBarBuilder pbBuilder() {
return new ProgressBarBuilder()
.setStyle(ProgressBarStyle.ASCII)
.setUpdateIntervalMillis(250)
.setMaxRenderedLength(75);
}
@SneakyThrows
public void execute() {
statistic.startTimer();
try (ProgressBar progressBar = pbBuilder().build()) {
List<File> files = loadFiles(Config.getInstance().getLibraryPath().getAbsolutePath());
progressBar.maxHint(files.size());
files.forEach(file -> executor.submit(() -> {
process(file);
progressBar.step();
}));
executor.shutdown();
executor.awaitTermination(1, TimeUnit.DAYS);
}
statistic.stopTimer();
statistic.printResult();
}
/**
* 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.
*
* @param file file or directory to update
*/
abstract void process(File file);
/**
* Persist file changes.
*
* @param fileInfoDto contains information about file and desired configuration.
*/
protected void updateFile(FileInfoDto fileInfoDto) {
statistic.total();
switch (fileInfoDto.getStatus()) {
case CHANGE_NECESSARY:
statistic.shouldChange();
commitChange(fileInfoDto);
break;
case UNABLE_TO_APPLY:
statistic.noSuitableConfigFound();
break;
case ALREADY_SUITED:
statistic.alreadyFits();
break;
case UNKNOWN:
default:
statistic.failure();
break;
}
}
private void commitChange(FileInfoDto fileInfo) {
if (Config.getInstance().isSafeMode()) {
return;
}
try {
processor.update(fileInfo.getFile(), fileInfo);
statistic.success();
log.info("Updated {}", fileInfo.getFile().getAbsolutePath());
} catch (IOException | MkvToolNixException e) {
statistic.failedChanging();
log.warn("File couldn't be updated: '{}', Error: {}", fileInfo.getFile().getAbsoluteFile(), e.getMessage());
}
}
}

View File

@@ -0,0 +1,32 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.kernel;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.FileCollector;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.FileProcessor;
import lombok.extern.slf4j.Slf4j;
import java.io.File;
import java.util.List;
@Slf4j
public class CoherentAttributeUpdaterKernel extends AttributeUpdaterKernel{
public CoherentAttributeUpdaterKernel(FileCollector collector, FileProcessor processor) {
super(collector, processor);
}
/**
* {@inheritDoc}
*/
@Override
List<File> loadFiles(String path) {
return null;
}
/**
* {@inheritDoc}
*/
@Override
void process(File file) {
}
}

View File

@@ -0,0 +1,63 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.kernel;
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.model.FileInfoDto;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import java.io.File;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
@Slf4j
public class DefaultAttributeUpdaterKernel extends AttributeUpdaterKernel {
public DefaultAttributeUpdaterKernel(FileCollector collector, FileProcessor processor) {
super(collector, processor);
}
/**
* {@inheritDoc}
*/
@Override
List<File> loadFiles(String path) {
List<File> excludedFiles = Config.getInstance().getExcludedDirectories().stream()
.map(collector::loadFiles)
.flatMap(Collection::stream)
.collect(Collectors.toList());
statistic.increaseTotalBy(excludedFiles.size());
statistic.increaseExcludedBy(excludedFiles.size());
return collector.loadFiles(Config.getInstance().getLibraryPath().getAbsolutePath()).stream()
.filter(file -> !excludedFiles.contains(file))
.collect(Collectors.toList());
}
/**
* {@inheritDoc}
*/
@Override
void process(File file) {
FileInfoDto fileInfo = new FileInfoDto(file);
List<FileAttribute> attributes = processor.loadAttributes(file);
// TODO: extract this to a attributeProcessor?
List<FileAttribute> nonForcedTracks = attributes.stream()
.filter(elem -> !StringUtils.containsAnyIgnoreCase(elem.getTrackName(),
Config.getInstance().getForcedKeywords().toArray(new CharSequence[0])))
.filter(elem -> !elem.isForcedTrack())
.collect(Collectors.toList());
List<FileAttribute> nonCommentaryTracks = attributes.stream()
.filter(elem -> !StringUtils.containsAnyIgnoreCase(elem.getTrackName(),
Config.getInstance().getCommentaryKeywords().toArray(new CharSequence[0])))
.collect(Collectors.toList());
processor.detectDefaultTracks(fileInfo, attributes, nonForcedTracks);
processor.detectDesiredTracks(fileInfo, nonForcedTracks, nonCommentaryTracks);
updateFile(fileInfo);
}
}