Improves configuration handling and stuff
	
		
			
	
		
	
	
		
	
		
			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:
		@@ -1,7 +1,6 @@
 | 
				
			|||||||
package net.knarcraft.ffmpegconverter;
 | 
					package net.knarcraft.ffmpegconverter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import net.knarcraft.ffmpegconverter.config.ConfigHandler;
 | 
					import net.knarcraft.ffmpegconverter.config.Configuration;
 | 
				
			||||||
import net.knarcraft.ffmpegconverter.config.ConfigKey;
 | 
					 | 
				
			||||||
import net.knarcraft.ffmpegconverter.converter.AnimeConverter;
 | 
					import net.knarcraft.ffmpegconverter.converter.AnimeConverter;
 | 
				
			||||||
import net.knarcraft.ffmpegconverter.converter.AudioConverter;
 | 
					import net.knarcraft.ffmpegconverter.converter.AudioConverter;
 | 
				
			||||||
import net.knarcraft.ffmpegconverter.converter.Converter;
 | 
					import net.knarcraft.ffmpegconverter.converter.Converter;
 | 
				
			||||||
@@ -15,9 +14,7 @@ import net.knarcraft.ffmpegconverter.converter.WebAnimeConverter;
 | 
				
			|||||||
import net.knarcraft.ffmpegconverter.converter.WebVideoConverter;
 | 
					import net.knarcraft.ffmpegconverter.converter.WebVideoConverter;
 | 
				
			||||||
import net.knarcraft.ffmpegconverter.property.MinimalSubtitlePreference;
 | 
					import net.knarcraft.ffmpegconverter.property.MinimalSubtitlePreference;
 | 
				
			||||||
import net.knarcraft.ffmpegconverter.utility.FileUtil;
 | 
					import net.knarcraft.ffmpegconverter.utility.FileUtil;
 | 
				
			||||||
import net.knarcraft.ffmpegconverter.utility.ListUtil;
 | 
					 | 
				
			||||||
import net.knarcraft.ffmpegconverter.utility.OutputUtil;
 | 
					import net.knarcraft.ffmpegconverter.utility.OutputUtil;
 | 
				
			||||||
import org.apache.commons.configuration2.Configuration;
 | 
					 | 
				
			||||||
import org.jetbrains.annotations.NotNull;
 | 
					import org.jetbrains.annotations.NotNull;
 | 
				
			||||||
import org.jetbrains.annotations.Nullable;
 | 
					import org.jetbrains.annotations.Nullable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -38,19 +35,10 @@ public class FFMpegConvert {
 | 
				
			|||||||
    private static final String FFMPEG_PATH = "ffmpeg"; //Can be just ffmpeg if it's in the path
 | 
					    private static final String FFMPEG_PATH = "ffmpeg"; //Can be just ffmpeg if it's in the path
 | 
				
			||||||
    private static final Scanner READER = new Scanner(System.in, StandardCharsets.UTF_8);
 | 
					    private static final Scanner READER = new Scanner(System.in, StandardCharsets.UTF_8);
 | 
				
			||||||
    private static Converter converter = null;
 | 
					    private static Converter converter = null;
 | 
				
			||||||
    private static final ConfigHandler configHandler = new ConfigHandler();
 | 
					    private static final Configuration configuration = new Configuration();
 | 
				
			||||||
    private static boolean debug = false;
 | 
					 | 
				
			||||||
    private static boolean useHardwareAcceleration = false;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static void main(@NotNull String[] arguments) throws IOException {
 | 
					    public static void main(@NotNull String[] arguments) throws IOException {
 | 
				
			||||||
        Configuration configuration = configHandler.load();
 | 
					        OutputUtil.setDebug(configuration.isDebugEnabled());
 | 
				
			||||||
        if (configuration.containsKey(ConfigKey.DEBUG.toString())) {
 | 
					 | 
				
			||||||
            debug = configuration.getBoolean(ConfigKey.DEBUG.toString());
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        OutputUtil.setDebug(debug);
 | 
					 | 
				
			||||||
        if (configuration.containsKey(ConfigKey.USE_HARDWARE_ACCELERATION.toString())) {
 | 
					 | 
				
			||||||
            useHardwareAcceleration = configuration.getBoolean(ConfigKey.USE_HARDWARE_ACCELERATION.toString());
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        converter = loadConverter();
 | 
					        converter = loadConverter();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -85,27 +73,10 @@ public class FFMpegConvert {
 | 
				
			|||||||
     * @return <p>The configuration handler</p>
 | 
					     * @return <p>The configuration handler</p>
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    @NotNull
 | 
					    @NotNull
 | 
				
			||||||
    public static ConfigHandler getConfigHandler() {
 | 
					    public static Configuration getConfiguration() {
 | 
				
			||||||
        return configHandler;
 | 
					        return configuration;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Gets whether debug mode is enabled
 | 
					 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     * @return <p>True if debug mode is enabled</p>
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    public static boolean isDebugEnabled() {
 | 
					 | 
				
			||||||
        return debug;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Gets whether hardware accelerated encoding is enabled
 | 
					 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     * @return <p>True if hardware accelerated encoding is enabled</p>
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    public static boolean useHardwareAcceleration() {
 | 
					 | 
				
			||||||
        return useHardwareAcceleration;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Asks the user which converter they want, and assigns a converter instance to the converter variable
 | 
					     * Asks the user which converter they want, and assigns a converter instance to the converter variable
 | 
				
			||||||
@@ -230,51 +201,37 @@ public class FFMpegConvert {
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    @Nullable
 | 
					    @Nullable
 | 
				
			||||||
    private static Converter generateAnimeConverter() {
 | 
					    private static Converter generateAnimeConverter() {
 | 
				
			||||||
        OutputUtil.println("[Audio languages jpn,eng,ger,fre] [Subtitle languages eng,ger,fre] [Minimal subtitle " +
 | 
					        OutputUtil.println("[Forced audio index 0-n] [Forced subtitle index 0-n] [Force video encoding true/false] " +
 | 
				
			||||||
                "preference REQUIRE/PREFER/NO_PREFERENCE/AVOID/REJECT] [Forced audio index 0-n] " +
 | 
					                "[Force audio encoding true/false] [Subtitle name filter]\nYour input: ");
 | 
				
			||||||
                "[Forced subtitle index 0-n] [Force video encoding true/false] [Force audio encoding true/false] " +
 | 
					        List<String> input = readInput(5);
 | 
				
			||||||
                "[Subtitle name filter]\nYour input: ");
 | 
					 | 
				
			||||||
        List<String> input = readInput(8);
 | 
					 | 
				
			||||||
        String[] audioLanguage = new String[]{"jpn", "nor", "eng", "0"};
 | 
					 | 
				
			||||||
        String[] subtitleLanguage = new String[]{"nob", "nor", "eng", "jpn", "0"};
 | 
					 | 
				
			||||||
        MinimalSubtitlePreference subtitlePreference = MinimalSubtitlePreference.AVOID;
 | 
					 | 
				
			||||||
        int forcedAudioIndex = 0;
 | 
					        int forcedAudioIndex = 0;
 | 
				
			||||||
        int forcedSubtitleIndex = 0;
 | 
					        int forcedSubtitleIndex = 0;
 | 
				
			||||||
        String subtitleNameFilter = "";
 | 
					        String subtitleNameFilter = "";
 | 
				
			||||||
        boolean forceVideoEncoding = false;
 | 
					        boolean forceVideoEncoding = false;
 | 
				
			||||||
        boolean forceAudioEncoding = false;
 | 
					        boolean forceAudioEncoding = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
            if (!input.isEmpty()) {
 | 
					            if (!input.isEmpty()) {
 | 
				
			||||||
            audioLanguage = ListUtil.getListFromCommaSeparatedString(input.get(0));
 | 
					                forcedAudioIndex = Integer.parseInt(input.get(0));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            if (input.size() > 1) {
 | 
					            if (input.size() > 1) {
 | 
				
			||||||
            subtitleLanguage = ListUtil.getListFromCommaSeparatedString(input.get(1));
 | 
					                forcedSubtitleIndex = Integer.parseInt(input.get(1));
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if (input.size() > 2) {
 | 
					 | 
				
			||||||
            subtitlePreference = MinimalSubtitlePreference.valueOf(input.get(2).toUpperCase());
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        try {
 | 
					 | 
				
			||||||
            if (input.size() > 3) {
 | 
					 | 
				
			||||||
                forcedAudioIndex = Integer.parseInt(input.get(3));
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            if (input.size() > 4) {
 | 
					 | 
				
			||||||
                forcedSubtitleIndex = Integer.parseInt(input.get(4));
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        } catch (NumberFormatException exception) {
 | 
					        } catch (NumberFormatException exception) {
 | 
				
			||||||
            OutputUtil.println("Forced audio or subtitle index is not a number");
 | 
					            OutputUtil.println("Forced audio or subtitle index is not a number");
 | 
				
			||||||
            return null;
 | 
					            return null;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (input.size() > 5) {
 | 
					        if (input.size() > 2) {
 | 
				
			||||||
            forceVideoEncoding = Boolean.parseBoolean(input.get(5));
 | 
					            forceVideoEncoding = Boolean.parseBoolean(input.get(2));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (input.size() > 6) {
 | 
					        if (input.size() > 3) {
 | 
				
			||||||
            forceAudioEncoding = Boolean.parseBoolean(input.get(6));
 | 
					            forceAudioEncoding = Boolean.parseBoolean(input.get(3));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (input.size() > 7) {
 | 
					        if (input.size() > 4) {
 | 
				
			||||||
            subtitleNameFilter = input.get(7);
 | 
					            subtitleNameFilter = input.get(4);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        return new AnimeConverter(FFPROBE_PATH, FFMPEG_PATH, audioLanguage, subtitleLanguage, subtitlePreference,
 | 
					        return new AnimeConverter(FFPROBE_PATH, FFMPEG_PATH, forcedAudioIndex, forcedSubtitleIndex, subtitleNameFilter,
 | 
				
			||||||
                forcedAudioIndex, forcedSubtitleIndex, subtitleNameFilter, forceVideoEncoding, forceAudioEncoding);
 | 
					                forceVideoEncoding, forceAudioEncoding);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@@ -284,12 +241,9 @@ public class FFMpegConvert {
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    @Nullable
 | 
					    @Nullable
 | 
				
			||||||
    private static Converter generateWebAnimeConverter() {
 | 
					    private static Converter generateWebAnimeConverter() {
 | 
				
			||||||
        OutputUtil.println("[Audio languages jpn,eng,ger,fre] [Subtitle languages eng,ger,fre] [Convert to stereo if " +
 | 
					        OutputUtil.println("[Convert to stereo if necessary true/false] [Prevent signs&songs subtitles true/false] [Forced audio index 0-n] " +
 | 
				
			||||||
                "necessary true/false] [Prevent signs&songs subtitles true/false] [Forced audio index 0-n] " +
 | 
					 | 
				
			||||||
                "[Forced subtitle index 0-n] [Subtitle name filter]\nYour input: ");
 | 
					                "[Forced subtitle index 0-n] [Subtitle name filter]\nYour input: ");
 | 
				
			||||||
        List<String> input = readInput(7);
 | 
					        List<String> input = readInput(5);
 | 
				
			||||||
        String[] audioLanguage = new String[]{"jpn", "0"};
 | 
					 | 
				
			||||||
        String[] subtitleLanguage = new String[]{"eng", "0"};
 | 
					 | 
				
			||||||
        boolean toStereo = true;
 | 
					        boolean toStereo = true;
 | 
				
			||||||
        MinimalSubtitlePreference subtitlePreference = MinimalSubtitlePreference.AVOID;
 | 
					        MinimalSubtitlePreference subtitlePreference = MinimalSubtitlePreference.AVOID;
 | 
				
			||||||
        int forcedAudioIndex = 0;
 | 
					        int forcedAudioIndex = 0;
 | 
				
			||||||
@@ -297,32 +251,26 @@ public class FFMpegConvert {
 | 
				
			|||||||
        String subtitleNameFilter = "";
 | 
					        String subtitleNameFilter = "";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!input.isEmpty()) {
 | 
					        if (!input.isEmpty()) {
 | 
				
			||||||
            audioLanguage = ListUtil.getListFromCommaSeparatedString(input.get(0));
 | 
					            toStereo = Boolean.parseBoolean(input.get(0));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (input.size() > 1) {
 | 
					        if (input.size() > 1) {
 | 
				
			||||||
            subtitleLanguage = ListUtil.getListFromCommaSeparatedString(input.get(1));
 | 
					            subtitlePreference = MinimalSubtitlePreference.valueOf(input.get(1).toUpperCase());
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if (input.size() > 2) {
 | 
					 | 
				
			||||||
            toStereo = Boolean.parseBoolean(input.get(2));
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if (input.size() > 3) {
 | 
					 | 
				
			||||||
            subtitlePreference = MinimalSubtitlePreference.valueOf(input.get(3).toUpperCase());
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            if (input.size() > 4) {
 | 
					            if (input.size() > 2) {
 | 
				
			||||||
                forcedAudioIndex = Integer.parseInt(input.get(4));
 | 
					                forcedAudioIndex = Integer.parseInt(input.get(2));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            if (input.size() > 5) {
 | 
					            if (input.size() > 3) {
 | 
				
			||||||
                forcedSubtitleIndex = Integer.parseInt(input.get(5));
 | 
					                forcedSubtitleIndex = Integer.parseInt(input.get(3));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        } catch (NumberFormatException exception) {
 | 
					        } catch (NumberFormatException exception) {
 | 
				
			||||||
            OutputUtil.println("Forced audio or subtitle index is not a number");
 | 
					            OutputUtil.println("Forced audio or subtitle index is not a number");
 | 
				
			||||||
            return null;
 | 
					            return null;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (input.size() > 6) {
 | 
					        if (input.size() > 4) {
 | 
				
			||||||
            subtitleNameFilter = input.get(6);
 | 
					            subtitleNameFilter = input.get(4);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        return new WebAnimeConverter(FFPROBE_PATH, FFMPEG_PATH, audioLanguage, subtitleLanguage, toStereo,
 | 
					        return new WebAnimeConverter(FFPROBE_PATH, FFMPEG_PATH, toStereo,
 | 
				
			||||||
                subtitlePreference, forcedAudioIndex, forcedSubtitleIndex, subtitleNameFilter);
 | 
					                subtitlePreference, forcedAudioIndex, forcedSubtitleIndex, subtitleNameFilter);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,10 +8,12 @@ import org.apache.commons.configuration2.builder.FileBasedConfigurationBuilder;
 | 
				
			|||||||
import org.apache.commons.configuration2.builder.fluent.Configurations;
 | 
					import org.apache.commons.configuration2.builder.fluent.Configurations;
 | 
				
			||||||
import org.apache.commons.configuration2.ex.ConfigurationException;
 | 
					import org.apache.commons.configuration2.ex.ConfigurationException;
 | 
				
			||||||
import org.jetbrains.annotations.NotNull;
 | 
					import org.jetbrains.annotations.NotNull;
 | 
				
			||||||
 | 
					import org.jetbrains.annotations.Nullable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.io.BufferedReader;
 | 
					import java.io.BufferedReader;
 | 
				
			||||||
import java.io.File;
 | 
					import java.io.File;
 | 
				
			||||||
import java.io.IOException;
 | 
					import java.io.IOException;
 | 
				
			||||||
 | 
					import java.util.HashMap;
 | 
				
			||||||
import java.util.Map;
 | 
					import java.util.Map;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@@ -23,6 +25,18 @@ public class ConfigHandler {
 | 
				
			|||||||
    private final Configurations configurations = new Configurations();
 | 
					    private final Configurations configurations = new Configurations();
 | 
				
			||||||
    private final File settingsFile = new File(configFolder, "config.properties");
 | 
					    private final File settingsFile = new File(configFolder, "config.properties");
 | 
				
			||||||
    private FileBasedConfigurationBuilder<PropertiesConfiguration> builder = configurations.propertiesBuilder(settingsFile);
 | 
					    private FileBasedConfigurationBuilder<PropertiesConfiguration> builder = configurations.propertiesBuilder(settingsFile);
 | 
				
			||||||
 | 
					    private final Map<ConfigKey<?>, Object> optionValues = new HashMap<>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Gets the current value of a configuration option
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param key <p>The configuration key to get the value of</p>
 | 
				
			||||||
 | 
					     * @return <p>The current value</p>
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    @Nullable
 | 
				
			||||||
 | 
					    public Object getValue(@NotNull ConfigKey<?> key) {
 | 
				
			||||||
 | 
					        return optionValues.get(key);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Gets a writable configuration used for changing settings
 | 
					     * Gets a writable configuration used for changing settings
 | 
				
			||||||
@@ -64,11 +78,9 @@ public class ConfigHandler {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Loads the saved configuration file
 | 
					     * Loads the saved configuration file
 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     * @return <p>The loaded configuration</p>
 | 
					 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    @NotNull
 | 
					    public void load() throws IOException {
 | 
				
			||||||
    public Configuration load() throws IOException {
 | 
					        optionValues.clear();
 | 
				
			||||||
        Configuration configuration;
 | 
					        Configuration configuration;
 | 
				
			||||||
        if (!settingsFile.exists()) {
 | 
					        if (!settingsFile.exists()) {
 | 
				
			||||||
            configuration = new PropertiesConfiguration();
 | 
					            configuration = new PropertiesConfiguration();
 | 
				
			||||||
@@ -86,7 +98,14 @@ public class ConfigHandler {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        // Reload contents in the builder
 | 
					        // Reload contents in the builder
 | 
				
			||||||
        builder = configurations.propertiesBuilder(settingsFile);
 | 
					        builder = configurations.propertiesBuilder(settingsFile);
 | 
				
			||||||
        return configuration;
 | 
					
 | 
				
			||||||
 | 
					        for (@NotNull ConfigKey<?> key : ConfigKey.values()) {
 | 
				
			||||||
 | 
					            if (configuration.containsKey(key.toString())) {
 | 
				
			||||||
 | 
					                optionValues.put(key, configuration.get(key.getType(), key.toString()));
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                optionValues.put(key, key.getDefaultValue());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,31 +2,106 @@ package net.knarcraft.ffmpegconverter.config;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import org.jetbrains.annotations.NotNull;
 | 
					import org.jetbrains.annotations.NotNull;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.HashSet;
 | 
				
			||||||
 | 
					import java.util.Set;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * A representation of all configuration keys
 | 
					 * A representation of all configuration keys
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public enum ConfigKey {
 | 
					public class ConfigKey<T> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static final Set<ConfigKey<?>> allKeys = new HashSet<>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * The configuration key for the list of hardware-accelerated encoders available on the system
 | 
					     * The configuration key for the list of hardware-accelerated encoders available on the system
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    HARDWARE_ACCELERATED_ENCODERS("encoders-hardware-accelerated"),
 | 
					    public static final ConfigKey<String> HARDWARE_ACCELERATED_ENCODERS = new ConfigKey<>("encoders-hardware-accelerated", String.class, "qsv,cuda,dxva2,d3d11va,opencl,vulkan");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * The configuration key for toggling debug mode
 | 
					     * The configuration key for toggling debug mode
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    DEBUG("debug"),
 | 
					    public static final ConfigKey<Boolean> DEBUG = createKey("debug", Boolean.class, false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * The configuration key for toggling hardware acceleration
 | 
					     * The configuration key for toggling hardware encoding
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    USE_HARDWARE_ACCELERATION("hardware-acceleration"),
 | 
					    public static final ConfigKey<Boolean> USE_HARDWARE_ENCODING = createKey("hardware-acceleration-encode", Boolean.class, false);
 | 
				
			||||||
    ;
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * The configuration key for toggling hardware decoding
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static final ConfigKey<Boolean> USE_HARDWARE_DECODING = createKey("hardware-acceleration-decode", Boolean.class, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * The configuration key for toggling forced flac encoding
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static final ConfigKey<Boolean> ENCODE_FLAC_ALWAYS = createKey("encode-flac-always", Boolean.class, false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * The configuration key for anime audio languages
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static final ConfigKey<String> AUDIO_LANGUAGES_ANIME = createKey("audio-languages-anime", String.class, "jpn,eng,*");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * The configuration key for anime subtitle languages
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static final ConfigKey<String> SUBTITLE_LANGUAGES_ANIME = createKey("subtitle-languages-anime", String.class, "eng,*");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * The configuration key for the minimal subtitle preference
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static final ConfigKey<String> MINIMAL_SUBTITLE_PREFERENCE = createKey("minimal-subtitle-preference", String.class, "AVOID");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private final String configKey;
 | 
					    private final String configKey;
 | 
				
			||||||
 | 
					    private final T defaultValue;
 | 
				
			||||||
 | 
					    private final Class<T> type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ConfigKey(@NotNull String configKey) {
 | 
					    /**
 | 
				
			||||||
 | 
					     * Instantiates a new config key
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param configKey    <p>The storage key in the configuration file</p>
 | 
				
			||||||
 | 
					     * @param type         <p>The type of this option's value</p>
 | 
				
			||||||
 | 
					     * @param defaultValue <p>The default value of this option</p>
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private ConfigKey(@NotNull String configKey, @NotNull Class<T> type, @NotNull T defaultValue) {
 | 
				
			||||||
        this.configKey = configKey;
 | 
					        this.configKey = configKey;
 | 
				
			||||||
 | 
					        this.type = type;
 | 
				
			||||||
 | 
					        this.defaultValue = defaultValue;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Creates a new config key
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param configKey    <p>The storage key in the configuration file</p>
 | 
				
			||||||
 | 
					     * @param type         <p>The type of this option's value</p>
 | 
				
			||||||
 | 
					     * @param defaultValue <p>The default value of this option</p>
 | 
				
			||||||
 | 
					     * @param <F>          <p>The type of key to create</p>
 | 
				
			||||||
 | 
					     * @return <p>The new config key</p>
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private static <F> ConfigKey<F> createKey(@NotNull String configKey, @NotNull Class<F> type, @NotNull F defaultValue) {
 | 
				
			||||||
 | 
					        ConfigKey<F> key = new ConfigKey<>(configKey, type, defaultValue);
 | 
				
			||||||
 | 
					        allKeys.add(key);
 | 
				
			||||||
 | 
					        return key;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Gets the type of this option's value
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return <p>The type of the value</p>
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    @NotNull
 | 
				
			||||||
 | 
					    public Class<T> getType() {
 | 
				
			||||||
 | 
					        return this.type;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Gets the default value for the option represented by this key
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return <p>The default value</p>
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    @NotNull
 | 
				
			||||||
 | 
					    public T getDefaultValue() {
 | 
				
			||||||
 | 
					        return this.defaultValue;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
@@ -34,4 +109,14 @@ public enum ConfigKey {
 | 
				
			|||||||
        return this.configKey;
 | 
					        return this.configKey;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Gets all configuration keys
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return <p>All configuration keys</p>
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    @NotNull
 | 
				
			||||||
 | 
					    public static ConfigKey<?>[] values() {
 | 
				
			||||||
 | 
					        return allKeys.toArray(new ConfigKey[0]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,150 @@
 | 
				
			|||||||
 | 
					package net.knarcraft.ffmpegconverter.config;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import net.knarcraft.ffmpegconverter.property.MinimalSubtitlePreference;
 | 
				
			||||||
 | 
					import net.knarcraft.ffmpegconverter.utility.ConfigHelper;
 | 
				
			||||||
 | 
					import org.jetbrains.annotations.NotNull;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.IOException;
 | 
				
			||||||
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * A configuration used for FFMpegConvert
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class Configuration {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private final ConfigHandler configHandler;
 | 
				
			||||||
 | 
					    private boolean debug;
 | 
				
			||||||
 | 
					    private boolean useHardwareEncoding;
 | 
				
			||||||
 | 
					    private boolean useHardwareDecoding;
 | 
				
			||||||
 | 
					    private List<String> hardwareEncoders;
 | 
				
			||||||
 | 
					    private boolean alwaysEncodeFlac;
 | 
				
			||||||
 | 
					    private List<String> animeAudioLanguages;
 | 
				
			||||||
 | 
					    private List<String> animeSubtitleLanguages;
 | 
				
			||||||
 | 
					    private MinimalSubtitlePreference minimalSubtitlePreference;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Instantiates and loads a new configuration
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public Configuration() {
 | 
				
			||||||
 | 
					        this.configHandler = new ConfigHandler();
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            this.configHandler.load();
 | 
				
			||||||
 | 
					        } catch (IOException e) {
 | 
				
			||||||
 | 
					            throw new RuntimeException(e);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        load();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Loads/reloads this configuration
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public void load() {
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            this.configHandler.load();
 | 
				
			||||||
 | 
					        } catch (IOException e) {
 | 
				
			||||||
 | 
					            throw new RuntimeException(e);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        debug = ConfigHelper.asBoolean(configHandler.getValue(ConfigKey.DEBUG));
 | 
				
			||||||
 | 
					        useHardwareEncoding = ConfigHelper.asBoolean(configHandler.getValue(ConfigKey.USE_HARDWARE_ENCODING));
 | 
				
			||||||
 | 
					        useHardwareDecoding = ConfigHelper.asBoolean(configHandler.getValue(ConfigKey.USE_HARDWARE_DECODING));
 | 
				
			||||||
 | 
					        hardwareEncoders = ConfigHelper.asStringList(configHandler.getValue(ConfigKey.HARDWARE_ACCELERATED_ENCODERS));
 | 
				
			||||||
 | 
					        alwaysEncodeFlac = ConfigHelper.asBoolean(configHandler.getValue(ConfigKey.ENCODE_FLAC_ALWAYS));
 | 
				
			||||||
 | 
					        animeAudioLanguages = ConfigHelper.asStringList(configHandler.getValue(ConfigKey.AUDIO_LANGUAGES_ANIME));
 | 
				
			||||||
 | 
					        animeSubtitleLanguages = ConfigHelper.asStringList(configHandler.getValue(ConfigKey.SUBTITLE_LANGUAGES_ANIME));
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            minimalSubtitlePreference = MinimalSubtitlePreference.valueOf(String.valueOf(configHandler.getValue(
 | 
				
			||||||
 | 
					                    ConfigKey.MINIMAL_SUBTITLE_PREFERENCE)));
 | 
				
			||||||
 | 
					        } catch (IllegalArgumentException | NullPointerException exception) {
 | 
				
			||||||
 | 
					            minimalSubtitlePreference = MinimalSubtitlePreference.AVOID;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Gets the underlying config handler for this configuration
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return <p>The underlying config handler</p>
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    @NotNull
 | 
				
			||||||
 | 
					    public ConfigHandler getConfigHandler() {
 | 
				
			||||||
 | 
					        return this.configHandler;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Gets whether debug mode is enabled
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return <p>True if debug mode is enabled</p>
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public boolean isDebugEnabled() {
 | 
				
			||||||
 | 
					        return this.debug;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Gets whether hardware accelerated encoding is enabled
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return <p>True if hardware accelerated encoding is enabled</p>
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public boolean useHardwareEncoding() {
 | 
				
			||||||
 | 
					        return this.useHardwareEncoding;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Gets whether hardware accelerated decoding is enabled
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return <p>True if hardware accelerated decoding is enabled</p>
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public boolean useHardwareDecoding() {
 | 
				
			||||||
 | 
					        return this.useHardwareDecoding;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Gets whether FLAC audio tracks should always be re-encoded
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return <p>Whether FLAC tracks should always be re-encoded</p>
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public boolean alwaysEncodeFlac() {
 | 
				
			||||||
 | 
					        return this.alwaysEncodeFlac;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Gets all hardware encoders defined in the configuration
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return <p>The specified hardware encoders</p>
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    @NotNull
 | 
				
			||||||
 | 
					    public List<String> hardwareEncoders() {
 | 
				
			||||||
 | 
					        return this.hardwareEncoders;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Gets the audio language priorities for usage when converting anime
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return <p>The anime audio language priorities</p>
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    @NotNull
 | 
				
			||||||
 | 
					    public List<String> getAnimeAudioLanguages() {
 | 
				
			||||||
 | 
					        return this.animeAudioLanguages;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Gets the subtitle language priorities for usage when converting anime
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return <p>The anime subtitle language priorities</p>
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    @NotNull
 | 
				
			||||||
 | 
					    public List<String> getAnimeSubtitleLanguages() {
 | 
				
			||||||
 | 
					        return this.animeSubtitleLanguages;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Gets the preference for minimal subtitles
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return <p>The minimal subtitle preference</p>
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    @NotNull
 | 
				
			||||||
 | 
					    public MinimalSubtitlePreference getMinimalSubtitlePreference() {
 | 
				
			||||||
 | 
					        return this.minimalSubtitlePreference;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -4,6 +4,7 @@ import net.knarcraft.ffmpegconverter.FFMpegConvert;
 | 
				
			|||||||
import net.knarcraft.ffmpegconverter.container.FFMpegCommand;
 | 
					import net.knarcraft.ffmpegconverter.container.FFMpegCommand;
 | 
				
			||||||
import net.knarcraft.ffmpegconverter.container.StreamProbeResult;
 | 
					import net.knarcraft.ffmpegconverter.container.StreamProbeResult;
 | 
				
			||||||
import net.knarcraft.ffmpegconverter.handler.AvailableHardwareEncoderHandler;
 | 
					import net.knarcraft.ffmpegconverter.handler.AvailableHardwareEncoderHandler;
 | 
				
			||||||
 | 
					import net.knarcraft.ffmpegconverter.streams.StreamObject;
 | 
				
			||||||
import net.knarcraft.ffmpegconverter.utility.FFMpegHelper;
 | 
					import net.knarcraft.ffmpegconverter.utility.FFMpegHelper;
 | 
				
			||||||
import net.knarcraft.ffmpegconverter.utility.FileHelper;
 | 
					import net.knarcraft.ffmpegconverter.utility.FileHelper;
 | 
				
			||||||
import net.knarcraft.ffmpegconverter.utility.FileUtil;
 | 
					import net.knarcraft.ffmpegconverter.utility.FileUtil;
 | 
				
			||||||
@@ -21,7 +22,7 @@ import java.util.List;
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
public abstract class AbstractConverter implements Converter {
 | 
					public abstract class AbstractConverter implements Converter {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    final boolean debug = FFMpegConvert.isDebugEnabled();
 | 
					    final boolean debug = FFMpegConvert.getConfiguration().isDebugEnabled();
 | 
				
			||||||
    private final String newExtension;
 | 
					    private final String newExtension;
 | 
				
			||||||
    protected String ffprobePath;
 | 
					    protected String ffprobePath;
 | 
				
			||||||
    protected String ffmpegPath;
 | 
					    protected String ffmpegPath;
 | 
				
			||||||
@@ -136,4 +137,18 @@ public abstract class AbstractConverter implements Converter {
 | 
				
			|||||||
        return encoderHandler.availableHardwareEncodings();
 | 
					        return encoderHandler.availableHardwareEncodings();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Sets the output indexes for the given streams
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * <p>This will basically mark the given streams' order as the order they will appear in the output file. This is
 | 
				
			||||||
 | 
					     * used when specifying specific codecs per-stream in the output file.</p>
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param streams <p>The streams to set the output indexes for</p>
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    protected <K extends StreamObject> void setOutputIndexes(@NotNull List<K> streams) {
 | 
				
			||||||
 | 
					        for (int i = 0; i < streams.size(); i++) {
 | 
				
			||||||
 | 
					            streams.get(i).setOutputIndex(i);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,7 @@
 | 
				
			|||||||
package net.knarcraft.ffmpegconverter.converter;
 | 
					package net.knarcraft.ffmpegconverter.converter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import net.knarcraft.ffmpegconverter.FFMpegConvert;
 | 
					import net.knarcraft.ffmpegconverter.FFMpegConvert;
 | 
				
			||||||
 | 
					import net.knarcraft.ffmpegconverter.config.Configuration;
 | 
				
			||||||
import net.knarcraft.ffmpegconverter.container.FFMpegCommand;
 | 
					import net.knarcraft.ffmpegconverter.container.FFMpegCommand;
 | 
				
			||||||
import net.knarcraft.ffmpegconverter.container.StreamProbeResult;
 | 
					import net.knarcraft.ffmpegconverter.container.StreamProbeResult;
 | 
				
			||||||
import net.knarcraft.ffmpegconverter.converter.module.ConverterModule;
 | 
					import net.knarcraft.ffmpegconverter.converter.module.ConverterModule;
 | 
				
			||||||
@@ -16,6 +17,7 @@ import net.knarcraft.ffmpegconverter.converter.module.output.CopyVideoModule;
 | 
				
			|||||||
import net.knarcraft.ffmpegconverter.converter.module.output.FastStartModule;
 | 
					import net.knarcraft.ffmpegconverter.converter.module.output.FastStartModule;
 | 
				
			||||||
import net.knarcraft.ffmpegconverter.converter.module.output.SetOutputFileModule;
 | 
					import net.knarcraft.ffmpegconverter.converter.module.output.SetOutputFileModule;
 | 
				
			||||||
import net.knarcraft.ffmpegconverter.converter.module.output.SetQualityModule;
 | 
					import net.knarcraft.ffmpegconverter.converter.module.output.SetQualityModule;
 | 
				
			||||||
 | 
					import net.knarcraft.ffmpegconverter.converter.module.output.SetStreamLanguageModule;
 | 
				
			||||||
import net.knarcraft.ffmpegconverter.converter.module.output.SetVideoCodecModule;
 | 
					import net.knarcraft.ffmpegconverter.converter.module.output.SetVideoCodecModule;
 | 
				
			||||||
import net.knarcraft.ffmpegconverter.converter.sorter.AudioLanguageSorter;
 | 
					import net.knarcraft.ffmpegconverter.converter.sorter.AudioLanguageSorter;
 | 
				
			||||||
import net.knarcraft.ffmpegconverter.converter.sorter.ForcedFirstSorter;
 | 
					import net.knarcraft.ffmpegconverter.converter.sorter.ForcedFirstSorter;
 | 
				
			||||||
@@ -29,10 +31,12 @@ import net.knarcraft.ffmpegconverter.streams.AudioStream;
 | 
				
			|||||||
import net.knarcraft.ffmpegconverter.streams.SubtitleStream;
 | 
					import net.knarcraft.ffmpegconverter.streams.SubtitleStream;
 | 
				
			||||||
import net.knarcraft.ffmpegconverter.streams.VideoStream;
 | 
					import net.knarcraft.ffmpegconverter.streams.VideoStream;
 | 
				
			||||||
import net.knarcraft.ffmpegconverter.utility.FFMpegHelper;
 | 
					import net.knarcraft.ffmpegconverter.utility.FFMpegHelper;
 | 
				
			||||||
 | 
					import net.knarcraft.ffmpegconverter.utility.OutputUtil;
 | 
				
			||||||
import org.jetbrains.annotations.NotNull;
 | 
					import org.jetbrains.annotations.NotNull;
 | 
				
			||||||
import org.jetbrains.annotations.Nullable;
 | 
					import org.jetbrains.annotations.Nullable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.ArrayList;
 | 
					import java.util.ArrayList;
 | 
				
			||||||
 | 
					import java.util.Arrays;
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@@ -40,8 +44,8 @@ import java.util.List;
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
public class AnimeConverter extends AbstractConverter {
 | 
					public class AnimeConverter extends AbstractConverter {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private final String[] audioLanguages;
 | 
					    private final List<String> audioLanguages;
 | 
				
			||||||
    private final String[] subtitleLanguages;
 | 
					    private final List<String> subtitleLanguages;
 | 
				
			||||||
    private final MinimalSubtitlePreference subtitlePreference;
 | 
					    private final MinimalSubtitlePreference subtitlePreference;
 | 
				
			||||||
    private final int forcedAudioIndex;
 | 
					    private final int forcedAudioIndex;
 | 
				
			||||||
    private final int forcedSubtitleIndex;
 | 
					    private final int forcedSubtitleIndex;
 | 
				
			||||||
@@ -54,25 +58,21 @@ public class AnimeConverter extends AbstractConverter {
 | 
				
			|||||||
     *
 | 
					     *
 | 
				
			||||||
     * @param ffprobePath         <p>Path/command to ffprobe.</p>
 | 
					     * @param ffprobePath         <p>Path/command to ffprobe.</p>
 | 
				
			||||||
     * @param ffmpegPath          <p>Path/command to ffmpeg.</p>
 | 
					     * @param ffmpegPath          <p>Path/command to ffmpeg.</p>
 | 
				
			||||||
     * @param audioLanguages      <p>List of wanted audio languages in descending order.</p>
 | 
					 | 
				
			||||||
     * @param subtitleLanguages   <p>List of wanted subtitle languages in descending order.</p>
 | 
					 | 
				
			||||||
     * @param subtitlePreference  <p>How minimal subtitles should be prioritized</p>
 | 
					 | 
				
			||||||
     * @param forcedAudioIndex    <p>A specific audio stream to force as default. 0-indexed from the first audio stream found</p>
 | 
					     * @param forcedAudioIndex    <p>A specific audio stream to force as default. 0-indexed from the first audio stream found</p>
 | 
				
			||||||
     * @param forcedSubtitleIndex <p>A specific subtitle stream to force as default. 0-indexed for the first subtitle stream found</p>
 | 
					     * @param forcedSubtitleIndex <p>A specific subtitle stream to force as default. 0-indexed for the first subtitle stream found</p>
 | 
				
			||||||
     * @param forceVideoEncoding  <p>Whether to enforce encoding on the video, even if already hevc</p>
 | 
					     * @param forceVideoEncoding  <p>Whether to enforce encoding on the video, even if already hevc</p>
 | 
				
			||||||
     * @param forceAudioEncoding  <p>Whether to convert audio to web-playable, even though there should be no need</p>
 | 
					     * @param forceAudioEncoding  <p>Whether to convert audio to web-playable, even though there should be no need</p>
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public AnimeConverter(@NotNull String ffprobePath, @NotNull String ffmpegPath, @NotNull String[] audioLanguages,
 | 
					    public AnimeConverter(@NotNull String ffprobePath, @NotNull String ffmpegPath, int forcedAudioIndex,
 | 
				
			||||||
                          @NotNull String[] subtitleLanguages,
 | 
					 | 
				
			||||||
                          @NotNull MinimalSubtitlePreference subtitlePreference, int forcedAudioIndex,
 | 
					 | 
				
			||||||
                          int forcedSubtitleIndex, @NotNull String subtitleNameFilter, boolean forceVideoEncoding,
 | 
					                          int forcedSubtitleIndex, @NotNull String subtitleNameFilter, boolean forceVideoEncoding,
 | 
				
			||||||
                          boolean forceAudioEncoding) {
 | 
					                          boolean forceAudioEncoding) {
 | 
				
			||||||
        super("mkv");
 | 
					        super("mkv");
 | 
				
			||||||
 | 
					        Configuration configuration = FFMpegConvert.getConfiguration();
 | 
				
			||||||
        this.ffprobePath = ffprobePath;
 | 
					        this.ffprobePath = ffprobePath;
 | 
				
			||||||
        this.ffmpegPath = ffmpegPath;
 | 
					        this.ffmpegPath = ffmpegPath;
 | 
				
			||||||
        this.audioLanguages = audioLanguages;
 | 
					        this.audioLanguages = configuration.getAnimeAudioLanguages();
 | 
				
			||||||
        this.subtitleLanguages = subtitleLanguages;
 | 
					        this.subtitleLanguages = configuration.getAnimeSubtitleLanguages();
 | 
				
			||||||
        this.subtitlePreference = subtitlePreference;
 | 
					        this.subtitlePreference = configuration.getMinimalSubtitlePreference();
 | 
				
			||||||
        this.forcedAudioIndex = forcedAudioIndex;
 | 
					        this.forcedAudioIndex = forcedAudioIndex;
 | 
				
			||||||
        this.forcedSubtitleIndex = forcedSubtitleIndex;
 | 
					        this.forcedSubtitleIndex = forcedSubtitleIndex;
 | 
				
			||||||
        this.subtitleNameFilter = subtitleNameFilter;
 | 
					        this.subtitleNameFilter = subtitleNameFilter;
 | 
				
			||||||
@@ -85,6 +85,7 @@ public class AnimeConverter extends AbstractConverter {
 | 
				
			|||||||
    public FFMpegCommand generateConversionCommand(@NotNull String executable,
 | 
					    public FFMpegCommand generateConversionCommand(@NotNull String executable,
 | 
				
			||||||
                                                   @NotNull StreamProbeResult probeResult,
 | 
					                                                   @NotNull StreamProbeResult probeResult,
 | 
				
			||||||
                                                   @NotNull String outFile) {
 | 
					                                                   @NotNull String outFile) {
 | 
				
			||||||
 | 
					        Configuration configuration = FFMpegConvert.getConfiguration();
 | 
				
			||||||
        FFMpegCommand command = FFMpegHelper.getFFMpegGeneralFileCommand(executable, probeResult.parsedFiles());
 | 
					        FFMpegCommand command = FFMpegHelper.getFFMpegGeneralFileCommand(executable, probeResult.parsedFiles());
 | 
				
			||||||
        List<ConverterModule> modules = new ArrayList<>();
 | 
					        List<ConverterModule> modules = new ArrayList<>();
 | 
				
			||||||
        if (this.debug) {
 | 
					        if (this.debug) {
 | 
				
			||||||
@@ -92,16 +93,20 @@ public class AnimeConverter extends AbstractConverter {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        modules.add(new FastStartModule());
 | 
					        modules.add(new FastStartModule());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        //Get the first video stream
 | 
					        //Map all video streams
 | 
				
			||||||
        modules.add(new MapAllModule<>(probeResult.getVideoStreams()));
 | 
					        List<VideoStream> videoStreams = probeResult.getVideoStreams();
 | 
				
			||||||
 | 
					        modules.add(new MapAllModule<>(videoStreams));
 | 
				
			||||||
 | 
					        setOutputIndexes(videoStreams);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        //Get the first audio stream in accordance with chosen languages
 | 
					        //Get the first audio stream in accordance with chosen languages
 | 
				
			||||||
        StreamSorter<AudioStream> audioSorter = new AudioLanguageSorter(this.audioLanguages)
 | 
					        StreamSorter<AudioStream> audioSorter = new AudioLanguageSorter(this.audioLanguages)
 | 
				
			||||||
                .append(new ForcedFirstSorter<>(this.forcedAudioIndex))
 | 
					                .append(new ForcedFirstSorter<>(this.forcedAudioIndex))
 | 
				
			||||||
                .append(new SpecialAudioSorter(MinimalSubtitlePreference.REJECT));
 | 
					                .append(new SpecialAudioSorter(MinimalSubtitlePreference.REJECT));
 | 
				
			||||||
        List<AudioStream> sortedAudio = audioSorter.chainSort(probeResult.getAudioStreams());
 | 
					        List<AudioStream> sortedAudio = audioSorter.chainSort(probeResult.getAudioStreams());
 | 
				
			||||||
 | 
					        setOutputIndexes(sortedAudio);
 | 
				
			||||||
        modules.add(new MapAllModule<>(sortedAudio));
 | 
					        modules.add(new MapAllModule<>(sortedAudio));
 | 
				
			||||||
        modules.add(new SetDefaultStreamModule<>(sortedAudio, 0));
 | 
					        modules.add(new SetDefaultStreamModule<>(sortedAudio, 0));
 | 
				
			||||||
 | 
					        modules.add(new SetStreamLanguageModule<>(sortedAudio));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        //Get the first subtitle stream in accordance with chosen languages and signs and songs prevention
 | 
					        //Get the first subtitle stream in accordance with chosen languages and signs and songs prevention
 | 
				
			||||||
        StreamSorter<SubtitleStream> subtitleSorter = new SubtitleTitleSorter(
 | 
					        StreamSorter<SubtitleStream> subtitleSorter = new SubtitleTitleSorter(
 | 
				
			||||||
@@ -109,13 +114,24 @@ public class AnimeConverter extends AbstractConverter {
 | 
				
			|||||||
                .append(new SubtitleLanguageSorter(this.subtitleLanguages))
 | 
					                .append(new SubtitleLanguageSorter(this.subtitleLanguages))
 | 
				
			||||||
                .append(new MinimalSubtitleSorter(this.subtitlePreference))
 | 
					                .append(new MinimalSubtitleSorter(this.subtitlePreference))
 | 
				
			||||||
                .append(new ForcedFirstSorter<>(this.forcedSubtitleIndex));
 | 
					                .append(new ForcedFirstSorter<>(this.forcedSubtitleIndex));
 | 
				
			||||||
        List<SubtitleStream> sorted = subtitleSorter.chainSort(probeResult.getSubtitleStreams());
 | 
					        List<SubtitleStream> sortedSubtitles = subtitleSorter.chainSort(probeResult.getSubtitleStreams());
 | 
				
			||||||
        modules.add(new MapAllModule<>(sorted));
 | 
					        setOutputIndexes(sortedSubtitles);
 | 
				
			||||||
        modules.add(new SetDefaultStreamModule<>(sorted, 0));
 | 
					        modules.add(new MapAllModule<>(sortedSubtitles));
 | 
				
			||||||
 | 
					        modules.add(new SetDefaultStreamModule<>(sortedSubtitles, 0));
 | 
				
			||||||
 | 
					        modules.add(new SetStreamLanguageModule<>(sortedSubtitles));
 | 
				
			||||||
 | 
					        OutputUtil.printDebug("Subtitle preference: " + this.subtitleLanguages + ", Subtitle name filter: " +
 | 
				
			||||||
 | 
					                this.subtitleNameFilter + ", Minimal Subtitle Preference: " + this.subtitlePreference.name() +
 | 
				
			||||||
 | 
					                ", Sorted order: " + Arrays.toString(sortedSubtitles.toArray()));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (configuration.useHardwareDecoding()) {
 | 
				
			||||||
            modules.add(new HardwareDecodeModule());
 | 
					            modules.add(new HardwareDecodeModule());
 | 
				
			||||||
        if (!this.forceAudioEncoding) {
 | 
					        }
 | 
				
			||||||
            modules.add(new CopyAudioModule());
 | 
					
 | 
				
			||||||
 | 
					        boolean encodeFlac = this.forceAudioEncoding || FFMpegConvert.getConfiguration().alwaysEncodeFlac();
 | 
				
			||||||
 | 
					        for (AudioStream audioStream : sortedAudio) {
 | 
				
			||||||
 | 
					            if (!encodeFlac || !audioStream.getCodecName().equalsIgnoreCase("flac")) {
 | 
				
			||||||
 | 
					                modules.add(new CopyAudioModule(audioStream));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        modules.add(new CopySubtitlesModule());
 | 
					        modules.add(new CopySubtitlesModule());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -129,10 +145,10 @@ public class AnimeConverter extends AbstractConverter {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        if (encodingNecessary || this.forceVideoEncoding) {
 | 
					        if (encodingNecessary || this.forceVideoEncoding) {
 | 
				
			||||||
            List<String> availableHWAcceleration = getAvailableHardwareEncodingMethods();
 | 
					            List<String> availableHWAcceleration = getAvailableHardwareEncodingMethods();
 | 
				
			||||||
            if (FFMpegConvert.useHardwareAcceleration() && availableHWAcceleration.contains("qsv")) {
 | 
					            if (configuration.useHardwareEncoding() && availableHWAcceleration.contains("qsv")) {
 | 
				
			||||||
                modules.add(new SetVideoCodecModule("hevc_qsv"));
 | 
					                modules.add(new SetVideoCodecModule("hevc_qsv"));
 | 
				
			||||||
                modules.add(new SetQualityModule(17, "veryslow"));
 | 
					                modules.add(new SetQualityModule(17, "veryslow"));
 | 
				
			||||||
            } else if (FFMpegConvert.useHardwareAcceleration() && availableHWAcceleration.contains("cuda")) {
 | 
					            } else if (configuration.useHardwareEncoding() && availableHWAcceleration.contains("cuda")) {
 | 
				
			||||||
                modules.add(new H265HardwareEncodingModule(20));
 | 
					                modules.add(new H265HardwareEncodingModule(20));
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                modules.add(new SetVideoCodecModule("hevc"));
 | 
					                modules.add(new SetVideoCodecModule("hevc"));
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,6 +12,7 @@ import net.knarcraft.ffmpegconverter.converter.module.output.CopyAudioModule;
 | 
				
			|||||||
import net.knarcraft.ffmpegconverter.converter.module.output.CopySubtitlesModule;
 | 
					import net.knarcraft.ffmpegconverter.converter.module.output.CopySubtitlesModule;
 | 
				
			||||||
import net.knarcraft.ffmpegconverter.converter.module.output.FastStartModule;
 | 
					import net.knarcraft.ffmpegconverter.converter.module.output.FastStartModule;
 | 
				
			||||||
import net.knarcraft.ffmpegconverter.converter.module.output.SetOutputFileModule;
 | 
					import net.knarcraft.ffmpegconverter.converter.module.output.SetOutputFileModule;
 | 
				
			||||||
 | 
					import net.knarcraft.ffmpegconverter.streams.AudioStream;
 | 
				
			||||||
import net.knarcraft.ffmpegconverter.streams.StreamObject;
 | 
					import net.knarcraft.ffmpegconverter.streams.StreamObject;
 | 
				
			||||||
import net.knarcraft.ffmpegconverter.utility.FFMpegHelper;
 | 
					import net.knarcraft.ffmpegconverter.utility.FFMpegHelper;
 | 
				
			||||||
import org.jetbrains.annotations.NotNull;
 | 
					import org.jetbrains.annotations.NotNull;
 | 
				
			||||||
@@ -64,9 +65,11 @@ public class MkvH264Converter extends AbstractConverter {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Map audio if present
 | 
					        // Map audio if present
 | 
				
			||||||
        if (!probeResult.getAudioStreams().isEmpty()) {
 | 
					        List<AudioStream> audioStreams = probeResult.getAudioStreams();
 | 
				
			||||||
            modules.add(new MapAllModule<>(probeResult.getAudioStreams()));
 | 
					        if (!audioStreams.isEmpty()) {
 | 
				
			||||||
            modules.add(new CopyAudioModule());
 | 
					            modules.add(new MapAllModule<>(audioStreams));
 | 
				
			||||||
 | 
					            setOutputIndexes(audioStreams);
 | 
				
			||||||
 | 
					            modules.add(new CopyAudioModule(audioStreams));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Map subtitles if present
 | 
					        // Map subtitles if present
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -69,7 +69,8 @@ public class MkvH265ReducedConverter extends AbstractConverter {
 | 
				
			|||||||
        List<AudioStream> audioStreams = probeResult.getAudioStreams();
 | 
					        List<AudioStream> audioStreams = probeResult.getAudioStreams();
 | 
				
			||||||
        if (!audioStreams.isEmpty()) {
 | 
					        if (!audioStreams.isEmpty()) {
 | 
				
			||||||
            modules.add(new MapAllModule<>(audioStreams));
 | 
					            modules.add(new MapAllModule<>(audioStreams));
 | 
				
			||||||
            modules.add(new CopyAudioModule());
 | 
					            setOutputIndexes(audioStreams);
 | 
				
			||||||
 | 
					            modules.add(new CopyAudioModule(audioStreams));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Map subtitles if present
 | 
					        // Map subtitles if present
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,8 +8,10 @@ import net.knarcraft.ffmpegconverter.converter.module.ModuleExecutor;
 | 
				
			|||||||
import net.knarcraft.ffmpegconverter.converter.module.hardwarecoding.HardwareDecodeModule;
 | 
					import net.knarcraft.ffmpegconverter.converter.module.hardwarecoding.HardwareDecodeModule;
 | 
				
			||||||
import net.knarcraft.ffmpegconverter.converter.module.mapping.MapAllModule;
 | 
					import net.knarcraft.ffmpegconverter.converter.module.mapping.MapAllModule;
 | 
				
			||||||
import net.knarcraft.ffmpegconverter.converter.module.output.CopyAudioModule;
 | 
					import net.knarcraft.ffmpegconverter.converter.module.output.CopyAudioModule;
 | 
				
			||||||
 | 
					import net.knarcraft.ffmpegconverter.converter.module.output.CopyVideoModule;
 | 
				
			||||||
import net.knarcraft.ffmpegconverter.converter.module.output.MovTextModule;
 | 
					import net.knarcraft.ffmpegconverter.converter.module.output.MovTextModule;
 | 
				
			||||||
import net.knarcraft.ffmpegconverter.converter.module.output.SetOutputFileModule;
 | 
					import net.knarcraft.ffmpegconverter.converter.module.output.SetOutputFileModule;
 | 
				
			||||||
 | 
					import net.knarcraft.ffmpegconverter.streams.AudioStream;
 | 
				
			||||||
import net.knarcraft.ffmpegconverter.utility.FFMpegHelper;
 | 
					import net.knarcraft.ffmpegconverter.utility.FFMpegHelper;
 | 
				
			||||||
import org.jetbrains.annotations.NotNull;
 | 
					import org.jetbrains.annotations.NotNull;
 | 
				
			||||||
import org.jetbrains.annotations.Nullable;
 | 
					import org.jetbrains.annotations.Nullable;
 | 
				
			||||||
@@ -53,8 +55,10 @@ public class SubtitleEmbed extends AbstractConverter {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        modules.add(new MapAllModule<>(probeResult.parsedStreams()));
 | 
					        modules.add(new MapAllModule<>(probeResult.parsedStreams()));
 | 
				
			||||||
        modules.add(new HardwareDecodeModule());
 | 
					        modules.add(new HardwareDecodeModule());
 | 
				
			||||||
        modules.add(new CopyAudioModule());
 | 
					        List<AudioStream> audioStreams = probeResult.getAudioStreams();
 | 
				
			||||||
        modules.add(new CopyAudioModule());
 | 
					        setOutputIndexes(audioStreams);
 | 
				
			||||||
 | 
					        modules.add(new CopyAudioModule(audioStreams));
 | 
				
			||||||
 | 
					        modules.add(new CopyVideoModule());
 | 
				
			||||||
        modules.add(new MovTextModule());
 | 
					        modules.add(new MovTextModule());
 | 
				
			||||||
        modules.add(new SetOutputFileModule(outFile));
 | 
					        modules.add(new SetOutputFileModule(outFile));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,7 @@
 | 
				
			|||||||
package net.knarcraft.ffmpegconverter.converter;
 | 
					package net.knarcraft.ffmpegconverter.converter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import net.knarcraft.ffmpegconverter.FFMpegConvert;
 | 
				
			||||||
 | 
					import net.knarcraft.ffmpegconverter.config.Configuration;
 | 
				
			||||||
import net.knarcraft.ffmpegconverter.container.FFMpegCommand;
 | 
					import net.knarcraft.ffmpegconverter.container.FFMpegCommand;
 | 
				
			||||||
import net.knarcraft.ffmpegconverter.container.StreamProbeResult;
 | 
					import net.knarcraft.ffmpegconverter.container.StreamProbeResult;
 | 
				
			||||||
import net.knarcraft.ffmpegconverter.converter.module.ConverterModule;
 | 
					import net.knarcraft.ffmpegconverter.converter.module.ConverterModule;
 | 
				
			||||||
@@ -33,8 +35,8 @@ import static net.knarcraft.ffmpegconverter.utility.FFMpegHelper.getNthSteam;
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
public class WebAnimeConverter extends AbstractConverter {
 | 
					public class WebAnimeConverter extends AbstractConverter {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private final String[] audioLanguages;
 | 
					    private final List<String> audioLanguages;
 | 
				
			||||||
    private final String[] subtitleLanguages;
 | 
					    private final List<String> subtitleLanguages;
 | 
				
			||||||
    private final boolean toStereo;
 | 
					    private final boolean toStereo;
 | 
				
			||||||
    private final MinimalSubtitlePreference subtitlePreference;
 | 
					    private final MinimalSubtitlePreference subtitlePreference;
 | 
				
			||||||
    private final int forcedAudioIndex;
 | 
					    private final int forcedAudioIndex;
 | 
				
			||||||
@@ -46,22 +48,20 @@ public class WebAnimeConverter extends AbstractConverter {
 | 
				
			|||||||
     *
 | 
					     *
 | 
				
			||||||
     * @param ffprobePath         <p>Path/command to ffprobe.</p>
 | 
					     * @param ffprobePath         <p>Path/command to ffprobe.</p>
 | 
				
			||||||
     * @param ffmpegPath          <p>Path/command to ffmpeg.</p>
 | 
					     * @param ffmpegPath          <p>Path/command to ffmpeg.</p>
 | 
				
			||||||
     * @param audioLanguages      <p>List of wanted audio languages in descending order.</p>
 | 
					 | 
				
			||||||
     * @param subtitleLanguages   <p>List of wanted subtitle languages in descending order.</p>
 | 
					 | 
				
			||||||
     * @param toStereo            <p>Convert video with several audio channels to stereo.</p>
 | 
					     * @param toStereo            <p>Convert video with several audio channels to stereo.</p>
 | 
				
			||||||
     * @param subtitlePreference  <p>How minimal subtitles should be prioritized</p>
 | 
					     * @param subtitlePreference  <p>How minimal subtitles should be prioritized</p>
 | 
				
			||||||
     * @param forcedAudioIndex    <p>A specific audio stream to force. 0-indexed from the first audio stream found</p>
 | 
					     * @param forcedAudioIndex    <p>A specific audio stream to force. 0-indexed from the first audio stream found</p>
 | 
				
			||||||
     * @param forcedSubtitleIndex <p>A specific subtitle stream to force. 0-indexed for the first subtitle stream found</p>
 | 
					     * @param forcedSubtitleIndex <p>A specific subtitle stream to force. 0-indexed for the first subtitle stream found</p>
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public WebAnimeConverter(@NotNull String ffprobePath, @NotNull String ffmpegPath, @NotNull String[] audioLanguages,
 | 
					    public WebAnimeConverter(@NotNull String ffprobePath, @NotNull String ffmpegPath, boolean toStereo,
 | 
				
			||||||
                             @NotNull String[] subtitleLanguages, boolean toStereo,
 | 
					 | 
				
			||||||
                             @NotNull MinimalSubtitlePreference subtitlePreference, int forcedAudioIndex,
 | 
					                             @NotNull MinimalSubtitlePreference subtitlePreference, int forcedAudioIndex,
 | 
				
			||||||
                             int forcedSubtitleIndex, @NotNull String subtitleNameFilter) {
 | 
					                             int forcedSubtitleIndex, @NotNull String subtitleNameFilter) {
 | 
				
			||||||
        super("mp4");
 | 
					        super("mp4");
 | 
				
			||||||
 | 
					        Configuration configuration = FFMpegConvert.getConfiguration();
 | 
				
			||||||
        this.ffprobePath = ffprobePath;
 | 
					        this.ffprobePath = ffprobePath;
 | 
				
			||||||
        this.ffmpegPath = ffmpegPath;
 | 
					        this.ffmpegPath = ffmpegPath;
 | 
				
			||||||
        this.audioLanguages = audioLanguages;
 | 
					        this.audioLanguages = configuration.getAnimeAudioLanguages();
 | 
				
			||||||
        this.subtitleLanguages = subtitleLanguages;
 | 
					        this.subtitleLanguages = configuration.getAnimeSubtitleLanguages();
 | 
				
			||||||
        this.toStereo = toStereo;
 | 
					        this.toStereo = toStereo;
 | 
				
			||||||
        this.subtitlePreference = subtitlePreference;
 | 
					        this.subtitlePreference = subtitlePreference;
 | 
				
			||||||
        this.forcedAudioIndex = forcedAudioIndex;
 | 
					        this.forcedAudioIndex = forcedAudioIndex;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,16 +2,56 @@ package net.knarcraft.ffmpegconverter.converter.module.output;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import net.knarcraft.ffmpegconverter.container.FFMpegCommand;
 | 
					import net.knarcraft.ffmpegconverter.container.FFMpegCommand;
 | 
				
			||||||
import net.knarcraft.ffmpegconverter.converter.module.ConverterModule;
 | 
					import net.knarcraft.ffmpegconverter.converter.module.ConverterModule;
 | 
				
			||||||
 | 
					import net.knarcraft.ffmpegconverter.streams.AudioStream;
 | 
				
			||||||
 | 
					import net.knarcraft.ffmpegconverter.streams.StreamObject;
 | 
				
			||||||
import org.jetbrains.annotations.NotNull;
 | 
					import org.jetbrains.annotations.NotNull;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * A module for making FFMpeg copy the audio codec
 | 
					 * A module for making FFMpeg copy the audio codec
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public class CopyAudioModule implements ConverterModule {
 | 
					public class CopyAudioModule implements ConverterModule {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private final List<AudioStream> streams;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Instantiates a new copy audio module
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param streams <p>The streams to specify the copy flag for, or null to not use a per-stream selector</p>
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public CopyAudioModule(@NotNull List<AudioStream> streams) {
 | 
				
			||||||
 | 
					        this.streams = streams;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Instantiates a new copy audio module
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param stream <p>The stream to specify the copy flag for</p>
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public CopyAudioModule(@NotNull AudioStream stream) {
 | 
				
			||||||
 | 
					        this.streams = List.of(stream);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Instantiates a new copy audio module
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public CopyAudioModule() {
 | 
				
			||||||
 | 
					        this.streams = null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void addArguments(@NotNull FFMpegCommand command) {
 | 
					    public void addArguments(@NotNull FFMpegCommand command) {
 | 
				
			||||||
 | 
					        if (this.streams != null) {
 | 
				
			||||||
 | 
					            for (StreamObject streamObject : this.streams) {
 | 
				
			||||||
 | 
					                int outputIndex = streamObject.getOutputIndex();
 | 
				
			||||||
 | 
					                if (outputIndex != -1) {
 | 
				
			||||||
 | 
					                    command.addOutputFileOption("-c:a:" + outputIndex, "copy");
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
            command.addOutputFileOption("-c:a", "copy");
 | 
					            command.addOutputFileOption("-c:a", "copy");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,38 @@
 | 
				
			|||||||
 | 
					package net.knarcraft.ffmpegconverter.converter.module.output;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import net.knarcraft.ffmpegconverter.container.FFMpegCommand;
 | 
				
			||||||
 | 
					import net.knarcraft.ffmpegconverter.converter.module.ConverterModule;
 | 
				
			||||||
 | 
					import net.knarcraft.ffmpegconverter.streams.StreamObject;
 | 
				
			||||||
 | 
					import org.jetbrains.annotations.NotNull;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * A module for setting the language of some streams
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param <K> <p>The type of stream to set language for</p>
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class SetStreamLanguageModule<K extends StreamObject> implements ConverterModule {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private final List<K> streams;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Instantiates a new set stream language module
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param streams <p>The streams to set language for</p>
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public SetStreamLanguageModule(@NotNull List<K> streams) {
 | 
				
			||||||
 | 
					        this.streams = streams;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void addArguments(@NotNull FFMpegCommand command) {
 | 
				
			||||||
 | 
					        for (StreamObject stream : this.streams) {
 | 
				
			||||||
 | 
					            if (!stream.getLanguage().equalsIgnoreCase("und") && !stream.getLanguage().isBlank()) {
 | 
				
			||||||
 | 
					                command.addOutputFileOption(String.format("-metadata:s:%s:%d", stream.streamTypeCharacter(),
 | 
				
			||||||
 | 
					                        stream.getOutputIndex()), String.format("language=%s", stream.getLanguage()));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -71,7 +71,7 @@ public abstract class AbstractSorter<L extends StreamObject> implements StreamSo
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    @NotNull
 | 
					    @NotNull
 | 
				
			||||||
    protected <G extends StreamObject> List<G> sortStreamsByLanguage(@NotNull List<G> streams,
 | 
					    protected <G extends StreamObject> List<G> sortStreamsByLanguage(@NotNull List<G> streams,
 | 
				
			||||||
                                                                     @NotNull String[] languages) {
 | 
					                                                                     @NotNull List<String> languages) {
 | 
				
			||||||
        List<G> sorted = new ArrayList<>();
 | 
					        List<G> sorted = new ArrayList<>();
 | 
				
			||||||
        for (String language : languages) {
 | 
					        for (String language : languages) {
 | 
				
			||||||
            for (G stream : streams) {
 | 
					            for (G stream : streams) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,14 +10,14 @@ import java.util.List;
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
public class AudioLanguageSorter extends AbstractSorter<AudioStream> {
 | 
					public class AudioLanguageSorter extends AbstractSorter<AudioStream> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private final String[] languageOrder;
 | 
					    private final List<String> languageOrder;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Instantiates a new audio language sorter
 | 
					     * Instantiates a new audio language sorter
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
     * @param languageOrder <p>The order of preference for audio languages</p>
 | 
					     * @param languageOrder <p>The order of preference for audio languages</p>
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public AudioLanguageSorter(@NotNull String[] languageOrder) {
 | 
					    public AudioLanguageSorter(@NotNull List<String> languageOrder) {
 | 
				
			||||||
        this.languageOrder = languageOrder;
 | 
					        this.languageOrder = languageOrder;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,14 +11,14 @@ import java.util.List;
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
public class SubtitleLanguageSorter extends AbstractSorter<SubtitleStream> {
 | 
					public class SubtitleLanguageSorter extends AbstractSorter<SubtitleStream> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private final String[] languageOrder;
 | 
					    private final List<String> languageOrder;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Instantiates a new subtitle language sorter
 | 
					     * Instantiates a new subtitle language sorter
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
     * @param languageOrder <p>The order of preference for subtitle languages</p>
 | 
					     * @param languageOrder <p>The order of preference for subtitle languages</p>
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public SubtitleLanguageSorter(@NotNull String[] languageOrder) {
 | 
					    public SubtitleLanguageSorter(@NotNull List<String> languageOrder) {
 | 
				
			||||||
        this.languageOrder = languageOrder;
 | 
					        this.languageOrder = languageOrder;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -45,7 +45,7 @@ public class SubtitleTitleSorter extends AbstractSorter<SubtitleStream> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            boolean isRegEx = isValidRegularExpression(filter) && hasSpecialRegexCharacters(filter);
 | 
					            boolean isRegEx = isValidRegularExpression(filter) && hasSpecialRegexCharacters(filter);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (FFMpegConvert.isDebugEnabled()) {
 | 
					            if (FFMpegConvert.getConfiguration().isDebugEnabled()) {
 | 
				
			||||||
                System.out.println("Filtering subtitles by filter " + filter + ". RegEx is " + isRegEx);
 | 
					                System.out.println("Filtering subtitles by filter " + filter + ". RegEx is " + isRegEx);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,7 +4,6 @@ import net.knarcraft.ffmpegconverter.FFMpegConvert;
 | 
				
			|||||||
import net.knarcraft.ffmpegconverter.config.ConfigHandler;
 | 
					import net.knarcraft.ffmpegconverter.config.ConfigHandler;
 | 
				
			||||||
import net.knarcraft.ffmpegconverter.config.ConfigKey;
 | 
					import net.knarcraft.ffmpegconverter.config.ConfigKey;
 | 
				
			||||||
import net.knarcraft.ffmpegconverter.utility.OutputUtil;
 | 
					import net.knarcraft.ffmpegconverter.utility.OutputUtil;
 | 
				
			||||||
import org.apache.commons.configuration2.Configuration;
 | 
					 | 
				
			||||||
import org.apache.commons.configuration2.PropertiesConfiguration;
 | 
					import org.apache.commons.configuration2.PropertiesConfiguration;
 | 
				
			||||||
import org.jetbrains.annotations.NotNull;
 | 
					import org.jetbrains.annotations.NotNull;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -17,7 +16,7 @@ import java.util.List;
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
public record AvailableHardwareEncoderHandler(@NotNull List<String> availableHardwareEncodings) {
 | 
					public record AvailableHardwareEncoderHandler(@NotNull List<String> availableHardwareEncodings) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private static final ConfigHandler configHandler = FFMpegConvert.getConfigHandler();
 | 
					    private static final ConfigHandler configHandler = FFMpegConvert.getConfiguration().getConfigHandler();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Gets all hardware encodings
 | 
					     * Gets all hardware encodings
 | 
				
			||||||
@@ -44,7 +43,7 @@ public record AvailableHardwareEncoderHandler(@NotNull List<String> availableHar
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public void save() {
 | 
					    public void save() {
 | 
				
			||||||
        PropertiesConfiguration configuration = configHandler.getWritableConfiguration();
 | 
					        PropertiesConfiguration configuration = configHandler.getWritableConfiguration();
 | 
				
			||||||
        configuration.setProperty(ConfigKey.HARDWARE_ACCELERATED_ENCODERS.toString(), this.availableHardwareEncodings);
 | 
					        configuration.setProperty(ConfigKey.HARDWARE_ACCELERATED_ENCODERS.toString(), String.join(",", this.availableHardwareEncodings));
 | 
				
			||||||
        configHandler.writeConfiguration();
 | 
					        configHandler.writeConfiguration();
 | 
				
			||||||
        OutputUtil.printDebug("Saved available hardware encoder handler");
 | 
					        OutputUtil.printDebug("Saved available hardware encoder handler");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -56,14 +55,12 @@ public record AvailableHardwareEncoderHandler(@NotNull List<String> availableHar
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    @NotNull
 | 
					    @NotNull
 | 
				
			||||||
    public static AvailableHardwareEncoderHandler load() {
 | 
					    public static AvailableHardwareEncoderHandler load() {
 | 
				
			||||||
        Configuration configuration;
 | 
					 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            configuration = configHandler.load();
 | 
					            configHandler.load();
 | 
				
			||||||
        } catch (IOException e) {
 | 
					        } catch (IOException e) {
 | 
				
			||||||
            throw new RuntimeException(e);
 | 
					            throw new RuntimeException(e);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        List<String> getEncodings = configuration.getList(String.class, ConfigKey.HARDWARE_ACCELERATED_ENCODERS.toString());
 | 
					        return new AvailableHardwareEncoderHandler(FFMpegConvert.getConfiguration().hardwareEncoders());
 | 
				
			||||||
        return new AvailableHardwareEncoderHandler(getEncodings);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,6 +17,7 @@ public abstract class AbstractStream implements StreamObject {
 | 
				
			|||||||
    protected final String language;
 | 
					    protected final String language;
 | 
				
			||||||
    protected final boolean isDefault;
 | 
					    protected final boolean isDefault;
 | 
				
			||||||
    protected final String title;
 | 
					    protected final String title;
 | 
				
			||||||
 | 
					    protected int outputIndex;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Instantiates a new abstract stream
 | 
					     * Instantiates a new abstract stream
 | 
				
			||||||
@@ -28,11 +29,12 @@ public abstract class AbstractStream implements StreamObject {
 | 
				
			|||||||
    protected AbstractStream(@NotNull Map<StreamTag, String> streamInfo, int inputIndex, int relativeIndex) {
 | 
					    protected AbstractStream(@NotNull Map<StreamTag, String> streamInfo, int inputIndex, int relativeIndex) {
 | 
				
			||||||
        this.codecName = ValueParsingHelper.parseString(streamInfo.get(StreamTag.CODEC_NAME), "");
 | 
					        this.codecName = ValueParsingHelper.parseString(streamInfo.get(StreamTag.CODEC_NAME), "");
 | 
				
			||||||
        this.absoluteIndex = ValueParsingHelper.parseInt(streamInfo.get(StreamTag.INDEX), -1);
 | 
					        this.absoluteIndex = ValueParsingHelper.parseInt(streamInfo.get(StreamTag.INDEX), -1);
 | 
				
			||||||
        this.language = ValueParsingHelper.parseString(streamInfo.get(StreamTag.TAG_LANGUAGE), "und");
 | 
					        this.language = parseLanguage(streamInfo);
 | 
				
			||||||
        this.isDefault = ValueParsingHelper.parseBoolean(streamInfo.get(StreamTag.DISPOSITION_DEFAULT), false);
 | 
					        this.isDefault = ValueParsingHelper.parseBoolean(streamInfo.get(StreamTag.DISPOSITION_DEFAULT), false);
 | 
				
			||||||
        this.title = ValueParsingHelper.parseString(streamInfo.get(StreamTag.TAG_TITLE), "");
 | 
					        this.title = ValueParsingHelper.parseString(streamInfo.get(StreamTag.TAG_TITLE), "");
 | 
				
			||||||
        this.inputIndex = inputIndex;
 | 
					        this.inputIndex = inputIndex;
 | 
				
			||||||
        this.relativeIndex = relativeIndex;
 | 
					        this.relativeIndex = relativeIndex;
 | 
				
			||||||
 | 
					        this.outputIndex = -1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
@@ -73,4 +75,40 @@ public abstract class AbstractStream implements StreamObject {
 | 
				
			|||||||
        return this.inputIndex;
 | 
					        return this.inputIndex;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public int getOutputIndex() {
 | 
				
			||||||
 | 
					        return this.outputIndex;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void setOutputIndex(int newIndex) {
 | 
				
			||||||
 | 
					        this.outputIndex = newIndex;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Parses the correct language of a stream
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * <p>As some people tend to set weird incorrect languages for anime streams, this tries to correct that by
 | 
				
			||||||
 | 
					     * detecting streams that are actually in english, but set to something else.</p>
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param streamInfo <p>All info about the stream</p>
 | 
				
			||||||
 | 
					     * @return <p>The actual language</p>
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    @NotNull
 | 
				
			||||||
 | 
					    private String parseLanguage(@NotNull Map<StreamTag, String> streamInfo) {
 | 
				
			||||||
 | 
					        String languageString = ValueParsingHelper.parseString(streamInfo.get(StreamTag.TAG_LANGUAGE), "und");
 | 
				
			||||||
 | 
					        String title = ValueParsingHelper.parseString(streamInfo.get(StreamTag.TAG_TITLE), "");
 | 
				
			||||||
 | 
					        if (languageString.equalsIgnoreCase("zxx") ||
 | 
				
			||||||
 | 
					                (title.toLowerCase().matches(".*english.*") && languageString.equalsIgnoreCase("jpn"))) {
 | 
				
			||||||
 | 
					            return "eng";
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return languageString;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    @NotNull
 | 
				
			||||||
 | 
					    public String toString() {
 | 
				
			||||||
 | 
					        return this.title + " | Input index: " + inputIndex + " | Language: " + language;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -5,6 +5,7 @@ import org.jetbrains.annotations.NotNull;
 | 
				
			|||||||
/**
 | 
					/**
 | 
				
			||||||
 * An object describing a generic video file stream
 | 
					 * An object describing a generic video file stream
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					@SuppressWarnings("unused")
 | 
				
			||||||
public interface StreamObject {
 | 
					public interface StreamObject {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@@ -68,4 +69,21 @@ public interface StreamObject {
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    char streamTypeCharacter();
 | 
					    char streamTypeCharacter();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Gets the index of this stream in the output file
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return <p>The index of this stream in the output file, or -1 if not set</p>
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    int getOutputIndex();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Sets the index of this stream in the output file
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * <p>After sorting and selecting streams, setting the output index makes it much easier to set properties for this
 | 
				
			||||||
 | 
					     * specific stream, without having to rely on loops</p>
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param newIndex <p>The new output index</p>
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    void setOutputIndex(int newIndex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -51,7 +51,7 @@ public class SubtitleStream extends AbstractStream implements StreamObject {
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    private boolean checkIfIsFullSubtitle() {
 | 
					    private boolean checkIfIsFullSubtitle() {
 | 
				
			||||||
        String titleLowercase = getTitle().toLowerCase().trim();
 | 
					        String titleLowercase = getTitle().toLowerCase().trim();
 | 
				
			||||||
        return !titleLowercase.matches(".*si(ng|gn)s?[ &/a-z]+songs?.*") &&
 | 
					        return !titleLowercase.matches(".*si(ng|gn)s?[ &/a-z+]+songs?.*") &&
 | 
				
			||||||
                !titleLowercase.matches(".*songs?[ &/a-z]+si(gn|ng)s?.*") &&
 | 
					                !titleLowercase.matches(".*songs?[ &/a-z]+si(gn|ng)s?.*") &&
 | 
				
			||||||
                !titleLowercase.matches(".*forced.*") &&
 | 
					                !titleLowercase.matches(".*forced.*") &&
 | 
				
			||||||
                !titleLowercase.matches(".*s&s.*") &&
 | 
					                !titleLowercase.matches(".*s&s.*") &&
 | 
				
			||||||
@@ -68,4 +68,10 @@ public class SubtitleStream extends AbstractStream implements StreamObject {
 | 
				
			|||||||
        return 's';
 | 
					        return 's';
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    @NotNull
 | 
				
			||||||
 | 
					    public String toString() {
 | 
				
			||||||
 | 
					        return super.toString() + " | Is full: " + this.isFullSubtitle;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,60 @@
 | 
				
			|||||||
 | 
					package net.knarcraft.ffmpegconverter.utility;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.jetbrains.annotations.NotNull;
 | 
				
			||||||
 | 
					import org.jetbrains.annotations.Nullable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.ArrayList;
 | 
				
			||||||
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * A helper class for dealing with configuration value types
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public final class ConfigHelper {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private ConfigHelper() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Gets the given value as a string list
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param value <p>The raw string list value</p>
 | 
				
			||||||
 | 
					     * @return <p>The value as a string list, or null if not compatible</p>
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static @NotNull List<String> asStringList(@Nullable Object value) {
 | 
				
			||||||
 | 
					        if (value == null) {
 | 
				
			||||||
 | 
					            return new ArrayList<>();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (value instanceof String string) {
 | 
				
			||||||
 | 
					            return List.of((string).split(","));
 | 
				
			||||||
 | 
					        } else if (value instanceof List<?> list) {
 | 
				
			||||||
 | 
					            List<String> strings = new ArrayList<>();
 | 
				
			||||||
 | 
					            for (Object object : list) {
 | 
				
			||||||
 | 
					                strings.add(String.valueOf(object));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return strings;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            return new ArrayList<>();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Gets the given value as a boolean
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * <p>This will throw an exception if used for a non-boolean value</p>
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param value <p>The object value to get</p>
 | 
				
			||||||
 | 
					     * @return <p>The value of the given object as a boolean</p>
 | 
				
			||||||
 | 
					     * @throws ClassCastException <p>If the given value is not a boolean</p>
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static boolean asBoolean(@Nullable Object value) throws ClassCastException {
 | 
				
			||||||
 | 
					        if (value instanceof Boolean booleanValue) {
 | 
				
			||||||
 | 
					            return booleanValue;
 | 
				
			||||||
 | 
					        } else if (value instanceof String) {
 | 
				
			||||||
 | 
					            return Boolean.parseBoolean((String) value);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            throw new ClassCastException();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -3,4 +3,16 @@
 | 
				
			|||||||
debug=false
 | 
					debug=false
 | 
				
			||||||
# Enabling hardware acceleration will try to use hardware acceleration for converters where it's available. Note that
 | 
					# Enabling hardware acceleration will try to use hardware acceleration for converters where it's available. Note that
 | 
				
			||||||
# software encoders generally produce a lower file-size relative to the output quality.
 | 
					# software encoders generally produce a lower file-size relative to the output quality.
 | 
				
			||||||
hardware-acceleration=false
 | 
					hardware-acceleration-encode=false
 | 
				
			||||||
 | 
					# Hardware decoding can often speed up the conversion, but might be troublesome at times
 | 
				
			||||||
 | 
					hardware-acceleration-decode=true
 | 
				
			||||||
 | 
					# The available hardware encoders
 | 
				
			||||||
 | 
					encoders-hardware-accelerated=qsv,cuda,vaapi,dxva2,d3d11va,opencl,vulkan,d3d12va
 | 
				
			||||||
 | 
					# As FLAC can increase file size significantly, this option enabled automatic re-encode of flac tracks
 | 
				
			||||||
 | 
					encode-flac-always=false
 | 
				
			||||||
 | 
					# The preference for audio languages when converting anime (0 = undefined, * = any)
 | 
				
			||||||
 | 
					audio-languages-anime=jpn,eng,*
 | 
				
			||||||
 | 
					# The preference for subtitle languages when converting anime (0 = undefined, * = any)
 | 
				
			||||||
 | 
					subtitle-languages-anime=eng,*
 | 
				
			||||||
 | 
					# The preference for minimal subtitles, AKA Signs & Songs (REQUIRE/PREFER/NO_PREFERENCE/AVOID/REJECT)
 | 
				
			||||||
 | 
					minimal-subtitle-preference=AVOID
 | 
				
			||||||
		Reference in New Issue
	
	Block a user