Adds filtering for audio description tracks
	
		
			
	
		
	
	
		
	
		
			All checks were successful
		
		
	
	
		
			
				
	
				KnarCraft/FFmpegConvert/pipeline/head This commit looks good
				
			
		
		
	
	
				
					
				
			
		
			All checks were successful
		
		
	
	KnarCraft/FFmpegConvert/pipeline/head This commit looks good
				
			This commit is contained in:
		@@ -20,6 +20,7 @@ import net.knarcraft.ffmpegconverter.converter.module.output.SetVideoCodecModule
 | 
			
		||||
import net.knarcraft.ffmpegconverter.converter.sorter.AudioLanguageSorter;
 | 
			
		||||
import net.knarcraft.ffmpegconverter.converter.sorter.ForcedFirstSorter;
 | 
			
		||||
import net.knarcraft.ffmpegconverter.converter.sorter.MinimalSubtitleSorter;
 | 
			
		||||
import net.knarcraft.ffmpegconverter.converter.sorter.SpecialAudioSorter;
 | 
			
		||||
import net.knarcraft.ffmpegconverter.converter.sorter.StreamSorter;
 | 
			
		||||
import net.knarcraft.ffmpegconverter.converter.sorter.SubtitleLanguageSorter;
 | 
			
		||||
import net.knarcraft.ffmpegconverter.converter.sorter.SubtitleTitleSorter;
 | 
			
		||||
@@ -95,8 +96,9 @@ public class AnimeConverter extends AbstractConverter {
 | 
			
		||||
        modules.add(new MapAllModule<>(probeResult.getVideoStreams()));
 | 
			
		||||
 | 
			
		||||
        //Get the first audio stream in accordance with chosen languages
 | 
			
		||||
        StreamSorter<AudioStream> audioSorter = new AudioLanguageSorter(this.audioLanguages).append(
 | 
			
		||||
                new ForcedFirstSorter<>(this.forcedAudioIndex));
 | 
			
		||||
        StreamSorter<AudioStream> audioSorter = new AudioLanguageSorter(this.audioLanguages)
 | 
			
		||||
                .append(new ForcedFirstSorter<>(this.forcedAudioIndex))
 | 
			
		||||
                .append(new SpecialAudioSorter(MinimalSubtitlePreference.REJECT));
 | 
			
		||||
        List<AudioStream> sortedAudio = audioSorter.chainSort(probeResult.getAudioStreams());
 | 
			
		||||
        modules.add(new MapAllModule<>(sortedAudio));
 | 
			
		||||
        modules.add(new SetDefaultStreamModule<>(sortedAudio, 0));
 | 
			
		||||
 
 | 
			
		||||
@@ -36,7 +36,7 @@ public class BurnSubtitleModule implements ConverterModule {
 | 
			
		||||
            FFMpegHelper.mapStream(command, videoStream);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (subtitleStream.getIsImageSubtitle()) {
 | 
			
		||||
        if (subtitleStream.isImageSubtitle()) {
 | 
			
		||||
            command.addOutputFileOption("-filter_complex",
 | 
			
		||||
                    String.format("[%d:%d]scale=width=%d:height=%d,crop=w=%d:h=%d:x=0:y=out_h[sub];[%d:%d][sub]overlay",
 | 
			
		||||
                            subtitleStream.getInputIndex(), subtitleStream.getAbsoluteIndex(), videoStream.getWidth(),
 | 
			
		||||
 
 | 
			
		||||
@@ -29,7 +29,7 @@ public class MinimalSubtitleSorter extends AbstractSorter<SubtitleStream> {
 | 
			
		||||
        List<SubtitleStream> fullSubtitles = new ArrayList<>();
 | 
			
		||||
        List<SubtitleStream> minimalSubtitles = new ArrayList<>();
 | 
			
		||||
        for (SubtitleStream subtitleStream : input) {
 | 
			
		||||
            if (subtitleStream.getIsFullSubtitle()) {
 | 
			
		||||
            if (subtitleStream.isFullSubtitle()) {
 | 
			
		||||
                fullSubtitles.add(subtitleStream);
 | 
			
		||||
            } else {
 | 
			
		||||
                minimalSubtitles.add(subtitleStream);
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,67 @@
 | 
			
		||||
package net.knarcraft.ffmpegconverter.converter.sorter;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.ffmpegconverter.property.MinimalSubtitlePreference;
 | 
			
		||||
import net.knarcraft.ffmpegconverter.streams.AudioStream;
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A sorter for sorting/filtering subtitles by a minimal subtitle preference
 | 
			
		||||
 */
 | 
			
		||||
public class SpecialAudioSorter extends AbstractSorter<AudioStream> {
 | 
			
		||||
 | 
			
		||||
    private final MinimalSubtitlePreference minimalSubtitlePreference;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Instantiates a new special audio preference sorter
 | 
			
		||||
     *
 | 
			
		||||
     * @param minimalSubtitlePreference <p>The minimal subtitle preference sort/filter by</p>
 | 
			
		||||
     */
 | 
			
		||||
    public SpecialAudioSorter(@NotNull MinimalSubtitlePreference minimalSubtitlePreference) {
 | 
			
		||||
        this.minimalSubtitlePreference = minimalSubtitlePreference;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public @NotNull List<AudioStream> sort(@NotNull List<AudioStream> input) {
 | 
			
		||||
        // Split all subtitles into full and minimal
 | 
			
		||||
        List<AudioStream> normalAudio = new ArrayList<>();
 | 
			
		||||
        List<AudioStream> specialAudio = new ArrayList<>();
 | 
			
		||||
        for (AudioStream audioStream : input) {
 | 
			
		||||
            if (audioStream.isSpecialAudio()) {
 | 
			
		||||
                specialAudio.add(audioStream);
 | 
			
		||||
            } else {
 | 
			
		||||
                normalAudio.add(audioStream);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Sort/filter subtitles based on full and minimal
 | 
			
		||||
        switch (this.minimalSubtitlePreference) {
 | 
			
		||||
            case REJECT -> {
 | 
			
		||||
                // Only return full subtitles
 | 
			
		||||
                return normalAudio;
 | 
			
		||||
            }
 | 
			
		||||
            case REQUIRE -> {
 | 
			
		||||
                // Only return minimal subtitles
 | 
			
		||||
                return specialAudio;
 | 
			
		||||
            }
 | 
			
		||||
            case NO_PREFERENCE -> {
 | 
			
		||||
                // Don't change order
 | 
			
		||||
                return input;
 | 
			
		||||
            }
 | 
			
		||||
            case PREFER -> {
 | 
			
		||||
                // Sort minimal subtitles first, and full subtitles last
 | 
			
		||||
                specialAudio.addAll(normalAudio);
 | 
			
		||||
                return specialAudio;
 | 
			
		||||
            }
 | 
			
		||||
            case AVOID -> {
 | 
			
		||||
                // Sort full subtitles first, and minimal subtitles last
 | 
			
		||||
                normalAudio.addAll(specialAudio);
 | 
			
		||||
                return normalAudio;
 | 
			
		||||
            }
 | 
			
		||||
            default -> throw new IllegalStateException("Unknown enum value encountered");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -11,6 +11,7 @@ import java.util.Map;
 | 
			
		||||
public class AudioStream extends AbstractStream implements StreamObject {
 | 
			
		||||
 | 
			
		||||
    private final int channels;
 | 
			
		||||
    private final boolean isSpecialAudio;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Instantiates a new audio stream
 | 
			
		||||
@@ -22,6 +23,16 @@ public class AudioStream extends AbstractStream implements StreamObject {
 | 
			
		||||
    public AudioStream(@NotNull Map<StreamTag, String> streamInfo, int inputIndex, int relativeIndex) {
 | 
			
		||||
        super(streamInfo, inputIndex, relativeIndex);
 | 
			
		||||
        this.channels = ValueParsingHelper.parseInt(streamInfo.get(StreamTag.CHANNELS), 0);
 | 
			
		||||
        this.isSpecialAudio = checkIfIsSpecialAudio();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets whether this audio stream is a special audio stream such as audio description or music only
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>True if this audio stream is a special audio stream</p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean isSpecialAudio() {
 | 
			
		||||
        return this.isSpecialAudio;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -38,4 +49,14 @@ public class AudioStream extends AbstractStream implements StreamObject {
 | 
			
		||||
        return 'a';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks whether this audio stream is a special audio stream
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>True if this is a special audio stream</p>
 | 
			
		||||
     */
 | 
			
		||||
    private boolean checkIfIsSpecialAudio() {
 | 
			
		||||
        String titleLowercase = getTitle().toLowerCase().trim();
 | 
			
		||||
        return titleLowercase.matches(".*audio description.*");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -9,8 +9,8 @@ import java.util.Map;
 | 
			
		||||
 */
 | 
			
		||||
public class SubtitleStream extends AbstractStream implements StreamObject {
 | 
			
		||||
 | 
			
		||||
    final private boolean isFullSubtitle;
 | 
			
		||||
    final private boolean isImageSubtitle;
 | 
			
		||||
    private final boolean isFullSubtitle;
 | 
			
		||||
    private final boolean isImageSubtitle;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Instantiates a new subtitle stream
 | 
			
		||||
@@ -21,7 +21,7 @@ public class SubtitleStream extends AbstractStream implements StreamObject {
 | 
			
		||||
     */
 | 
			
		||||
    public SubtitleStream(@NotNull Map<StreamTag, String> streamInfo, int inputIndex, int relativeIndex) {
 | 
			
		||||
        super(streamInfo, inputIndex, relativeIndex);
 | 
			
		||||
        this.isFullSubtitle = isFullSubtitle();
 | 
			
		||||
        this.isFullSubtitle = checkIfIsFullSubtitle();
 | 
			
		||||
        this.isImageSubtitle = codecName != null &&
 | 
			
		||||
                (getCodecName().equals("hdmv_pgs_subtitle") || getCodecName().equals("dvd_subtitle"));
 | 
			
		||||
    }
 | 
			
		||||
@@ -31,7 +31,7 @@ public class SubtitleStream extends AbstractStream implements StreamObject {
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>Whether the subtitles is an image subtitle.</p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean getIsImageSubtitle() {
 | 
			
		||||
    public boolean isImageSubtitle() {
 | 
			
		||||
        return this.isImageSubtitle;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -40,7 +40,7 @@ public class SubtitleStream extends AbstractStream implements StreamObject {
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>Whether the subtitle is a full subtitle.</p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean getIsFullSubtitle() {
 | 
			
		||||
    public boolean isFullSubtitle() {
 | 
			
		||||
        return this.isFullSubtitle;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -49,7 +49,7 @@ public class SubtitleStream extends AbstractStream implements StreamObject {
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>True if the subtitle translates everything.</p>
 | 
			
		||||
     */
 | 
			
		||||
    private boolean isFullSubtitle() {
 | 
			
		||||
    private boolean checkIfIsFullSubtitle() {
 | 
			
		||||
        String titleLowercase = getTitle().toLowerCase().trim();
 | 
			
		||||
        return !titleLowercase.matches(".*si(ng|gn)s?[ &/a-z]+songs?.*") &&
 | 
			
		||||
                !titleLowercase.matches(".*songs?[ &/a-z]+si(gn|ng)s?.*") &&
 | 
			
		||||
@@ -59,7 +59,8 @@ public class SubtitleStream extends AbstractStream implements StreamObject {
 | 
			
		||||
                !titleLowercase.matches("songs?") &&
 | 
			
		||||
                !titleLowercase.matches(".*signs only.*") &&
 | 
			
		||||
                !titleLowercase.matches(".* signs .*") &&
 | 
			
		||||
                !titleLowercase.matches("signs@.*");
 | 
			
		||||
                !titleLowercase.matches("signs@.*") &&
 | 
			
		||||
                !titleLowercase.matches("signs -.*");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user