diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/converter/AttributeConfigConverter.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/converter/AttributeConfigConverter.java index ba4e5e2..a8aae70 100644 --- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/converter/AttributeConfigConverter.java +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/converter/AttributeConfigConverter.java @@ -37,10 +37,10 @@ public class AttributeConfigConverter implements CommandLine.ITypeConverter filterForPossibleDefaults(List tracks) { + /** + * Looks for default matches and applies them if found. + */ + public void findAndApplyDefaultMatch(FileInfo fileInfo, AttributeConfig... configs) { + Map> audiosByLanguage = new HashMap<>(fileInfo.getTracks().size()); + Map> 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 getPossibleDefaults(List tracks) { Stream 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> audiosByLanguage = new HashMap<>(fileInfo.getTracks().size()); - Map> 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> tracks, String language, Supplier 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 changes = fileInfo.getChanges().getDefaultTrack(); + if (changes.containsKey(targetDefault)) { + changes.remove(targetDefault); + } else { + changes.put(targetDefault, true); } } - public void findForcedTracksAndApplyChanges(FileInfo fileInfo, boolean overwrite) { - Stream 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 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 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) diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/processors/CoherentAttributeUpdater.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/processors/CoherentAttributeUpdater.java index 24e356c..f156189 100644 --- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/processors/CoherentAttributeUpdater.java +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/processors/CoherentAttributeUpdater.java @@ -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()) { diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/processors/SingleFileAttributeUpdater.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/processors/SingleFileAttributeUpdater.java index 0d28a08..a8c64ee 100644 --- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/processors/SingleFileAttributeUpdater.java +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/processors/SingleFileAttributeUpdater.java @@ -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); } diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/model/AttributeConfig.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/model/AttributeConfig.java index 45b278e..f9c30ab 100644 --- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/model/AttributeConfig.java +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/model/AttributeConfig.java @@ -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 + '\'' + '}'; } } diff --git a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/processors/AttributeChangeProcessorTest.java b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/processors/AttributeChangeProcessorTest.java index 67b9f6e..d12fa27 100644 --- a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/processors/AttributeChangeProcessorTest.java +++ b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/processors/AttributeChangeProcessorTest.java @@ -18,7 +18,24 @@ import static org.junit.jupiter.api.Assertions.assertTrue; class AttributeChangeProcessorTest { - private static Stream attributeConfigMatching() { + 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 on(TrackAttributes track) { + return Map.entry(track, true); + } + + private static Map.Entry off(TrackAttributes track) { + return Map.entry(track, false); + } + + private static Stream findAndApplyDefaultMatch() { return Stream.of( Arguments.of( List.of(withName(AUDIO_ENG, null), SUB_ENG), @@ -99,13 +116,14 @@ class AttributeChangeProcessorTest { } @ParameterizedTest - @MethodSource("attributeConfigMatching") - void findDefaultMatchAndApplyChanges(List tracks, AttributeConfig[] config, String expectedConfig, Map changes) { + @MethodSource("findAndApplyDefaultMatch") + void findAndApplyDefaultMatch(List tracks, AttributeConfig[] config, String expectedConfig, Map changes) { AttributeChangeProcessor attributeChangeProcessor = new AttributeChangeProcessor(new String[]{}, Set.of("forced"), Set.of("commentary"), Set.of("SDH")); - FileInfo fileInfo = new FileInfo(null); fileInfo.addTracks(tracks); - attributeChangeProcessor.findDefaultMatchAndApplyChanges(fileInfo, config); + + attributeChangeProcessor.findAndApplyDefaultMatch(fileInfo, config); + assertEquals(expectedConfig, fileInfo.getMatchedConfig() != null ? fileInfo.getMatchedConfig().toStringShort() : fileInfo.getMatchedConfig()); assertEquals(changes.size(), fileInfo.getChanges().getDefaultTrack().size()); changes.forEach((key, value) -> { @@ -114,24 +132,54 @@ class AttributeChangeProcessorTest { }); } - private static AttributeConfig[] arr(AttributeConfig... configs) { - return configs; + private static Stream applyForcedAsDefault() { + return Stream.of( + Arguments.of( + List.of(AUDIO_GER, SUB_GER_FORCED), + a("ger:OFF"), + Map.ofEntries(on(SUB_GER_FORCED)) + ), + Arguments.of( + List.of(AUDIO_GER, SUB_GER_FORCED, SUB_GER), + a("ger:OFF"), + Map.ofEntries(on(SUB_GER_FORCED)) + ), + Arguments.of( + List.of(AUDIO_GER, withName(SUB_GER, "forced")), + a("ger:OFF"), + Map.ofEntries(on(withName(SUB_GER, "forced"))) + ), + Arguments.of( + List.of(AUDIO_GER, SUB_GER_FORCED, SUB_ENG), + a("ger:eng"), + Map.ofEntries() + ), + Arguments.of( + List.of(AUDIO_GER, SUB_GER_FORCED, SUB_ENG), + null, + Map.ofEntries() + ) + ); } - private static AttributeConfig a(String config) { - String[] split = config.split(":"); - return new AttributeConfig(split[0], split[1]); + @ParameterizedTest + @MethodSource("applyForcedAsDefault") + void applyForcedAsDefault(List tracks, AttributeConfig config, Map changes) { + AttributeChangeProcessor attributeChangeProcessor = new AttributeChangeProcessor(new String[]{}, Set.of("forced"), Set.of(""), Set.of("")); + FileInfo fileInfo = new FileInfo(null); + fileInfo.addTracks(tracks); + fileInfo.setMatchedConfig(config); + + attributeChangeProcessor.applyForcedAsDefault(fileInfo); + + 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 Map.Entry on(TrackAttributes track) { - return Map.entry(track, true); - } - - private static Map.Entry off(TrackAttributes track) { - return Map.entry(track, false); - } - - private static Stream filterForPossibleDefaults() { + private static Stream getPossibleDefaults() { return Stream.of( Arguments.of(List.of(AUDIO_GER, AUDIO_ENG, SUB_GER), Set.of(AUDIO_GER, AUDIO_ENG, SUB_GER)), Arguments.of(List.of(AUDIO_GER, AUDIO_ENG, withName(AUDIO_GER, "forced"), SUB_GER), Set.of(AUDIO_GER, AUDIO_ENG, SUB_GER)), @@ -145,24 +193,55 @@ class AttributeChangeProcessorTest { } @ParameterizedTest - @MethodSource("filterForPossibleDefaults") - void filterForPossibleDefaults(List tracks, Set expected) throws InvocationTargetException, IllegalAccessException { + @MethodSource("getPossibleDefaults") + void getPossibleDefaults(List tracks, Set expected) throws InvocationTargetException, IllegalAccessException { AttributeChangeProcessor attributeChangeProcessor = new AttributeChangeProcessor(new String[]{}, Set.of("forced"), Set.of("commentary"), Set.of("SDH")); Optional method = Arrays.stream(AttributeChangeProcessor.class.getDeclaredMethods()) - .filter(m -> m.getName().equals("filterForPossibleDefaults")) + .filter(m -> m.getName().equals("getPossibleDefaults")) .findFirst(); assertTrue(method.isPresent()); Method underTest = method.get(); underTest.setAccessible(true); - List result = (List) underTest.invoke(attributeChangeProcessor, tracks); + List result = ((Stream) underTest.invoke(attributeChangeProcessor, tracks)).toList(); assertEquals(expected.size(), result.size()); for (TrackAttributes track : result) { assertTrue(expected.contains(track)); } } - private static Stream findForcedTracksAndApplyChanges() { + private static Stream getForcedTracks() { + return Stream.of( + Arguments.of(List.of(withName(SUB_GER, "forced")), Map.of(), Set.of(withName(SUB_GER, "forced"))), + Arguments.of(List.of(SUB_GER_FORCED), Map.of(), Set.of(SUB_GER_FORCED)), + Arguments.of(List.of(SUB_GER_FORCED, withName(SUB_GER, "forced")), Map.of(), Set.of(SUB_GER_FORCED, withName(SUB_GER, "forced"))), + Arguments.of(List.of(SUB_GER_FORCED, withName(SUB_GER, "forced")), Map.of(SUB_GER_FORCED, false), Set.of(withName(SUB_GER, "forced"))), + Arguments.of(List.of(SUB_GER, withName(SUB_GER, "forced")), Map.of(SUB_GER, true), Set.of(SUB_GER, withName(SUB_GER, "forced"))) + ); + } + + @ParameterizedTest + @MethodSource("getForcedTracks") + void getForcedTracks(List tracks, Map changes, Set expected) throws InvocationTargetException, IllegalAccessException { + AttributeChangeProcessor attributeChangeProcessor = new AttributeChangeProcessor(new String[]{}, Set.of("forced"), Set.of(), Set.of()); + FileInfo fileInfo = new FileInfo(null); + fileInfo.addTracks(tracks); + changes.forEach((key, val) -> fileInfo.getChanges().getForcedTrack().put(key, val)); + Optional method = Arrays.stream(AttributeChangeProcessor.class.getDeclaredMethods()) + .filter(m -> m.getName().equals("getForcedTracks")) + .findFirst(); + + assertTrue(method.isPresent()); + Method underTest = method.get(); + underTest.setAccessible(true); + List result = ((Stream) underTest.invoke(attributeChangeProcessor, fileInfo)).toList(); + assertEquals(expected.size(), result.size()); + for (TrackAttributes track : result) { + assertTrue(expected.contains(track)); + } + } + + private static Stream findAndApplyForcedTracks() { return Stream.of( Arguments.of(List.of(), Set.of("song & signs"), false, @@ -196,13 +275,13 @@ class AttributeChangeProcessorTest { } @ParameterizedTest - @MethodSource("findForcedTracksAndApplyChanges") - void findForcedTracksAndApplyChanges(List tracks, Set keywords, boolean overwrite, Map changes) { + @MethodSource("findAndApplyForcedTracks") + void findAndApplyForcedTracks(List tracks, Set keywords, boolean overwrite, Map changes) { AttributeChangeProcessor attributeChangeProcessor = new AttributeChangeProcessor(new String[]{}, keywords, Set.of(), Set.of()); FileInfo fileInfo = new FileInfo(null); fileInfo.addTracks(tracks); - attributeChangeProcessor.findForcedTracksAndApplyChanges(fileInfo, overwrite); + attributeChangeProcessor.findAndApplyForcedTracks(fileInfo, overwrite); assertEquals(changes.size(), fileInfo.getChanges().getForcedTrack().size()); changes.forEach((key, value) -> { @@ -211,7 +290,7 @@ class AttributeChangeProcessorTest { }); } - private static Stream findCommentaryTracksAndApplyChanges() { + private static Stream findAndApplyCommentaryTracks() { return Stream.of( Arguments.of(List.of(withName(SUB_GER, "commentary"), withName(SUB_GER, null)), Set.of("commentary"), @@ -233,13 +312,13 @@ class AttributeChangeProcessorTest { } @ParameterizedTest - @MethodSource("findCommentaryTracksAndApplyChanges") - void findCommentaryTracksAndApplyChanges(List tracks, Set keywords, Map changes) { + @MethodSource("findAndApplyCommentaryTracks") + void findAndApplyCommentaryTracks(List tracks, Set keywords, Map changes) { AttributeChangeProcessor attributeChangeProcessor = new AttributeChangeProcessor(new String[]{}, Set.of(), keywords, Set.of()); FileInfo fileInfo = new FileInfo(null); fileInfo.addTracks(tracks); - attributeChangeProcessor.findCommentaryTracksAndApplyChanges(fileInfo); + attributeChangeProcessor.findAndApplyCommentaryTracks(fileInfo); assertEquals(changes.size(), fileInfo.getChanges().getCommentaryTrack().size()); changes.forEach((key, value) -> { @@ -248,7 +327,7 @@ class AttributeChangeProcessorTest { }); } - private static Stream findHearingImpairedTracksAndApplyChanges() { + private static Stream findAndApplyHearingImpairedTracks() { return Stream.of( Arguments.of(List.of(withName(SUB_GER, "SDH"), withName(SUB_GER, null)), Set.of("SDH"), @@ -270,13 +349,13 @@ class AttributeChangeProcessorTest { } @ParameterizedTest - @MethodSource("findHearingImpairedTracksAndApplyChanges") - void findHearingImpairedTracksAndApplyChanges(List tracks, Set keywords, Map changes) { + @MethodSource("findAndApplyHearingImpairedTracks") + void findAndApplyHearingImpairedTracks(List tracks, Set keywords, Map changes) { AttributeChangeProcessor attributeChangeProcessor = new AttributeChangeProcessor(new String[]{}, Set.of(), Set.of(), keywords); FileInfo fileInfo = new FileInfo(null); fileInfo.addTracks(tracks); - attributeChangeProcessor.findHearingImpairedTracksAndApplyChanges(fileInfo); + attributeChangeProcessor.findAndApplyHearingImpairedTracks(fileInfo); assertEquals(changes.size(), fileInfo.getChanges().getHearingImpairedTrack().size()); changes.forEach((key, value) -> {