Apply forced track if sub lang is OFF

This commit is contained in:
RatzzFatzz
2025-12-24 16:22:17 +01:00
parent 13283e3765
commit f18fdbdda6
6 changed files with 207 additions and 101 deletions

View File

@@ -37,10 +37,10 @@ public class AttributeConfigConverter implements CommandLine.ITypeConverter<Attr
* @return valid {@link AttributeConfig}
*/
private static AttributeConfig validateResult(AttributeConfig attr) {
if (!isLanguageValid(attr.getAudioLanguage()))
throw new CommandLine.TypeConversionException("Audio language invalid: " + attr.getAudioLanguage());
if (!isLanguageValid(attr.getSubtitleLanguage()))
throw new CommandLine.TypeConversionException("Subtitle language invalid: " + attr.getSubtitleLanguage());
if (!isLanguageValid(attr.getAudioLang()))
throw new CommandLine.TypeConversionException("Audio language invalid: " + attr.getAudioLang());
if (!isLanguageValid(attr.getSubLang()))
throw new CommandLine.TypeConversionException("Subtitle language invalid: " + attr.getSubLang());
return attr;
}

View File

@@ -4,8 +4,6 @@ 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 AttributeChangeProcessor {
@@ -21,7 +19,51 @@ public class AttributeChangeProcessor {
this.forcedKeywords = forcedKeywords;
}
private List<TrackAttributes> filterForPossibleDefaults(List<TrackAttributes> tracks) {
/**
* Looks for default matches and applies them if found.
*/
public void findAndApplyDefaultMatch(FileInfo fileInfo, AttributeConfig... configs) {
Map<String, List<TrackAttributes>> audiosByLanguage = new HashMap<>(fileInfo.getTracks().size());
Map<String, List<TrackAttributes>> subsByLanguage = new HashMap<>(fileInfo.getTracks().size());
getPossibleDefaults(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.getAudioLang()) || audiosByLanguage.containsKey(config.getAudioLang()))
&& ("OFF".equals(config.getSubLang()) || subsByLanguage.containsKey(config.getSubLang()))) {
fileInfo.setMatchedConfig(config);
break;
}
}
if (fileInfo.getMatchedConfig() == null) return;
AttributeConfig match = fileInfo.getMatchedConfig();
removeExistingDefaults(fileInfo);
if (!"OFF".equals(match.getAudioLang())) applyNewDefault(fileInfo, audiosByLanguage.get(fileInfo.getMatchedConfig().getAudioLang()).get(0));
if (!"OFF".equals(match.getSubLang())) applyNewDefault(fileInfo, subsByLanguage.get(fileInfo.getMatchedConfig().getSubLang()).stream().max(subtitleTrackComparator).get());
}
/**
* If match with xxx:OFF was found forced track in audio language is applied as default.
* Forced track detection takes changes of {@link AttributeChangeProcessor#findAndApplyForcedTracks} into consideration.
*/
public void applyForcedAsDefault(FileInfo fileInfo) {
AttributeConfig c = fileInfo.getMatchedConfig();
if (c == null) return;
if (!"OFF".equals(c.getAudioLang()) && "OFF".equals(c.getSubLang())) {
getForcedTracks(fileInfo)
.filter(track -> c.getAudioLang().equals(track.language()))
.findFirst()
.ifPresent(track -> applyNewDefault(fileInfo, track));
}
}
private Stream<TrackAttributes> getPossibleDefaults(List<TrackAttributes> tracks) {
Stream<TrackAttributes> attributes = tracks.stream();
return attributes
@@ -34,55 +76,26 @@ public class AttributeChangeProcessor {
.filter(attr -> {
if (attr.trackName() == null) return true;
return forcedKeywords.stream().noneMatch(keyword -> keyword.compareToIgnoreCase(attr.trackName()) == 0);
})
.toList();
});
}
public 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 void applyDefaultChanges(FileInfo fileInfo, Function<FileInfo, List<TrackAttributes>> tracks, String language, Supplier<TrackAttributes> targetDefaultSupplier) {
tracks.apply(fileInfo).stream()
private void removeExistingDefaults(FileInfo fileInfo) {
fileInfo.getTracks().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);
}
}
private void applyNewDefault(FileInfo fileInfo, TrackAttributes targetDefault) {
Map<TrackAttributes, Boolean> changes = fileInfo.getChanges().getDefaultTrack();
if (changes.containsKey(targetDefault)) {
changes.remove(targetDefault);
} else {
changes.put(targetDefault, true);
}
}
public void findForcedTracksAndApplyChanges(FileInfo fileInfo, boolean overwrite) {
Stream<TrackAttributes> forcedTracks = fileInfo.getTracks().stream()
.filter(track -> track.trackName() != null)
.filter(track -> forcedKeywords.stream().anyMatch(keyword -> track.trackName().toLowerCase().contains(keyword.toLowerCase(Locale.ROOT))));
public void findAndApplyForcedTracks(FileInfo fileInfo, boolean overwrite) {
Stream<TrackAttributes> forcedTracks = getForcedTracks(fileInfo);
if (overwrite) {
fileInfo.getTracks().stream().filter(TrackAttributes::forced).forEach(attr -> {
@@ -97,7 +110,19 @@ public class AttributeChangeProcessor {
});
}
public void findCommentaryTracksAndApplyChanges(FileInfo fileInfo) {
private Stream<TrackAttributes> getForcedTracks(FileInfo fileInfo) {
return fileInfo.getTracks().stream()
.filter(track -> {
if (fileInfo.getChanges().getForcedTrack().containsKey(track)) return fileInfo.getChanges().getForcedTrack().get(track);
return matchesForcedKeywords(track) || track.forced();
});
}
private boolean matchesForcedKeywords(TrackAttributes track) {
return track.trackName() != null && forcedKeywords.stream().anyMatch(keyword -> track.trackName().toLowerCase().contains(keyword.toLowerCase(Locale.ROOT)));
}
public void findAndApplyCommentaryTracks(FileInfo fileInfo) {
fileInfo.getTracks().stream()
.filter(track -> !track.commentary())
.filter(track -> track.trackName() != null)
@@ -107,7 +132,7 @@ public class AttributeChangeProcessor {
});
}
public void findHearingImpairedTracksAndApplyChanges(FileInfo fileInfo) {
public void findAndApplyHearingImpairedTracks(FileInfo fileInfo) {
fileInfo.getTracks().stream()
.filter(track -> !track.hearingImpaired())
.filter(track -> track.trackName() != null)

View File

@@ -49,9 +49,10 @@ public class CoherentAttributeUpdater extends SingleFileAttributeUpdater {
log.info("Found coherent match {} for {}", matchedConfig.toStringShort(), rootDir.getPath());
matchedFiles.forEach(fileInfo -> {
attributeChangeProcessor.findForcedTracksAndApplyChanges(fileInfo, this.config.isOverwriteForced());
attributeChangeProcessor.findCommentaryTracksAndApplyChanges(fileInfo);
attributeChangeProcessor.findHearingImpairedTracksAndApplyChanges(fileInfo);
attributeChangeProcessor.findAndApplyForcedTracks(fileInfo, this.config.isOverwriteForced());
attributeChangeProcessor.applyForcedAsDefault(fileInfo);
attributeChangeProcessor.findAndApplyCommentaryTracks(fileInfo);
attributeChangeProcessor.findAndApplyHearingImpairedTracks(fileInfo);
checkStatusAndUpdate(fileInfo);
});
@@ -89,7 +90,7 @@ public class CoherentAttributeUpdater extends SingleFileAttributeUpdater {
break;
}
attributeChangeProcessor.findDefaultMatchAndApplyChanges(fileInfo, config);
attributeChangeProcessor.findAndApplyDefaultMatch(fileInfo, config);
if (matchedConfig == null) matchedConfig = fileInfo.getMatchedConfig();
if (matchedConfig == null || matchedConfig != fileInfo.getMatchedConfig()) {

View File

@@ -36,10 +36,11 @@ public class SingleFileAttributeUpdater extends AttributeUpdater {
return;
}
attributeChangeProcessor.findDefaultMatchAndApplyChanges(fileInfo, config.getAttributeConfig());
attributeChangeProcessor.findForcedTracksAndApplyChanges(fileInfo, config.isOverwriteForced());
attributeChangeProcessor.findCommentaryTracksAndApplyChanges(fileInfo);
attributeChangeProcessor.findHearingImpairedTracksAndApplyChanges(fileInfo);
attributeChangeProcessor.findAndApplyDefaultMatch(fileInfo, config.getAttributeConfig());
attributeChangeProcessor.findAndApplyForcedTracks(fileInfo, config.isOverwriteForced());
attributeChangeProcessor.applyForcedAsDefault(fileInfo);
attributeChangeProcessor.findAndApplyCommentaryTracks(fileInfo);
attributeChangeProcessor.findAndApplyHearingImpairedTracks(fileInfo);
checkStatusAndUpdate(fileInfo);
}

View File

@@ -10,8 +10,8 @@ import java.util.Objects;
@Getter
@AllArgsConstructor
public class AttributeConfig {
private final String audioLanguage;
private final String subtitleLanguage;
private final String audioLang;
private final String subLang;
public static AttributeConfig of(String audioLanguage, String subtitleLanguage) {
return new AttributeConfig(audioLanguage, subtitleLanguage);
@@ -22,23 +22,23 @@ public class AttributeConfig {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
AttributeConfig that = (AttributeConfig) o;
return Objects.equals(audioLanguage, that.audioLanguage) && Objects.equals(subtitleLanguage, that.subtitleLanguage);
return Objects.equals(audioLang, that.audioLang) && Objects.equals(subLang, that.subLang);
}
@Override
public int hashCode() {
return Objects.hash(audioLanguage, subtitleLanguage);
return Objects.hash(audioLang, subLang);
}
public String toStringShort() {
return audioLanguage + ":" + subtitleLanguage;
return audioLang + ":" + subLang;
}
@Override
public String toString() {
return "AttributeConfig{"
+ "audioLanguage='" + audioLanguage + '\''
+ ", subtitleLanguage='" + subtitleLanguage + '\'' +
+ "audioLanguage='" + audioLang + '\''
+ ", subtitleLanguage='" + subLang + '\'' +
'}';
}
}