Makes it possible to enable debug mode
	
		
			
	
		
	
	
		
	
		
			Some checks failed
		
		
	
	
		
			
				
	
				KnarCraft/FFmpegConvert/pipeline/head There was a failure building this commit
				
			
		
		
	
	
				
					
				
			
		
			Some checks failed
		
		
	
	KnarCraft/FFmpegConvert/pipeline/head There was a failure building this commit
				
			Debug mode is now enabled if the property `debug = true` is set in `conf/config.properties` Changes code for reading internal configurations Changes many primitive lists to List<> Adds some missing annotations Renames the main class
This commit is contained in:
		@@ -1,5 +1,6 @@
 | 
			
		||||
package net.knarcraft.ffmpegconverter;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.ffmpegconverter.config.ConfigHandler;
 | 
			
		||||
import net.knarcraft.ffmpegconverter.converter.AnimeConverter;
 | 
			
		||||
import net.knarcraft.ffmpegconverter.converter.AudioConverter;
 | 
			
		||||
import net.knarcraft.ffmpegconverter.converter.Converter;
 | 
			
		||||
@@ -15,11 +16,13 @@ import net.knarcraft.ffmpegconverter.property.MinimalSubtitlePreference;
 | 
			
		||||
import net.knarcraft.ffmpegconverter.utility.FileUtil;
 | 
			
		||||
import net.knarcraft.ffmpegconverter.utility.ListUtil;
 | 
			
		||||
import net.knarcraft.ffmpegconverter.utility.OutputUtil;
 | 
			
		||||
import org.apache.commons.configuration2.Configuration;
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
import org.jetbrains.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.nio.charset.StandardCharsets;
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Scanner;
 | 
			
		||||
 | 
			
		||||
@@ -28,15 +31,23 @@ import static net.knarcraft.ffmpegconverter.utility.Parser.tokenize;
 | 
			
		||||
/**
 | 
			
		||||
 * The main class for starting the software
 | 
			
		||||
 */
 | 
			
		||||
class Main {
 | 
			
		||||
public class FFMpegConvert {
 | 
			
		||||
 | 
			
		||||
    private static final String FFPROBE_PATH = "ffprobe"; //Can be just ffprobe 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 Converter converter = null;
 | 
			
		||||
    private static final ConfigHandler configHandler = new ConfigHandler();
 | 
			
		||||
    private static boolean debug = false;
 | 
			
		||||
 | 
			
		||||
    public static void main(String[] args) throws IOException {
 | 
			
		||||
    public static void main(@NotNull String[] arguments) throws IOException {
 | 
			
		||||
        Configuration configuration = configHandler.load();
 | 
			
		||||
        if (configuration.containsKey("debug")) {
 | 
			
		||||
            debug = configuration.getBoolean("debug");
 | 
			
		||||
        }
 | 
			
		||||
        OutputUtil.setDebug(debug);
 | 
			
		||||
        converter = loadConverter();
 | 
			
		||||
 | 
			
		||||
        if (converter == null) {
 | 
			
		||||
            System.exit(1);
 | 
			
		||||
            return;
 | 
			
		||||
@@ -62,9 +73,29 @@ class Main {
 | 
			
		||||
        OutputUtil.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the configuration handler
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The configuration handler</p>
 | 
			
		||||
     */
 | 
			
		||||
    @NotNull
 | 
			
		||||
    public static ConfigHandler getConfigHandler() {
 | 
			
		||||
        return configHandler;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets whether debug mode is enabled
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>True if debug mode is enabled</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static boolean isDebugEnabled() {
 | 
			
		||||
        return debug;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Asks the user which converter they want, and assigns a converter instance to the converter variable
 | 
			
		||||
     */
 | 
			
		||||
    @Nullable
 | 
			
		||||
    private static Converter loadConverter() {
 | 
			
		||||
        int choice = getChoice("""
 | 
			
		||||
                Which converter do you want do use?
 | 
			
		||||
@@ -101,7 +132,7 @@ class Main {
 | 
			
		||||
     * @param recursionSteps <p>The depth to recurse if a folder is given.</p>
 | 
			
		||||
     * @throws IOException <p>If conversion or writing fails.</p>
 | 
			
		||||
     */
 | 
			
		||||
    private static void convertAllFiles(File fileOrFolder, int recursionSteps) throws IOException {
 | 
			
		||||
    private static void convertAllFiles(@NotNull File fileOrFolder, int recursionSteps) throws IOException {
 | 
			
		||||
        if (fileOrFolder.isDirectory()) {
 | 
			
		||||
            File[] files = FileUtil.listFilesRecursive(fileOrFolder, converter.getValidFormats(), recursionSteps);
 | 
			
		||||
            if (files != null && files.length > 0) {
 | 
			
		||||
@@ -113,7 +144,7 @@ class Main {
 | 
			
		||||
            }
 | 
			
		||||
        } else if (fileOrFolder.exists()) {
 | 
			
		||||
            String path = fileOrFolder.getPath();
 | 
			
		||||
            if (Arrays.stream(converter.getValidFormats()).anyMatch((format) -> format.equalsIgnoreCase(
 | 
			
		||||
            if (converter.getValidFormats().stream().anyMatch((format) -> format.equalsIgnoreCase(
 | 
			
		||||
                    path.substring(path.lastIndexOf('.') + 1)))) {
 | 
			
		||||
                converter.convert(fileOrFolder);
 | 
			
		||||
            } else {
 | 
			
		||||
@@ -130,6 +161,7 @@ class Main {
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The initialized downscale converter</p>
 | 
			
		||||
     */
 | 
			
		||||
    @Nullable
 | 
			
		||||
    private static Converter generateDownScaleConverter() {
 | 
			
		||||
        OutputUtil.println("(New width e.x. 1920) (New height e.x. 1080)\nYour input: ");
 | 
			
		||||
        List<String> input = readInput(3);
 | 
			
		||||
@@ -151,6 +183,7 @@ class Main {
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The initialized transcoder</p>
 | 
			
		||||
     */
 | 
			
		||||
    @Nullable
 | 
			
		||||
    private static Converter generateMKVToMP4Transcoder() {
 | 
			
		||||
        OutputUtil.println("[Audio stream index 0-n] [Subtitle stream index 0-n] [Video stream index 0-n]\nYour input: ");
 | 
			
		||||
        List<String> input = readInput(3);
 | 
			
		||||
@@ -180,6 +213,7 @@ class Main {
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The initialized anime converter</p>
 | 
			
		||||
     */
 | 
			
		||||
    @Nullable
 | 
			
		||||
    private static Converter generateAnimeConverter() {
 | 
			
		||||
        OutputUtil.println("[Audio languages jpn,eng,ger,fre] [Subtitle languages eng,ger,fre] [Minimal subtitle " +
 | 
			
		||||
                "preference REQUIRE/PREFER/NO_PREFERENCE/AVOID/REJECT] [Forced audio index 0-n] " +
 | 
			
		||||
@@ -224,6 +258,7 @@ class Main {
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The initialized anime converter</p>
 | 
			
		||||
     */
 | 
			
		||||
    @Nullable
 | 
			
		||||
    private static Converter generateWebAnimeConverter() {
 | 
			
		||||
        OutputUtil.println("[Audio languages jpn,eng,ger,fre] [Subtitle languages eng,ger,fre] [Convert to stereo if " +
 | 
			
		||||
                "necessary true/false] [Prevent signs&songs subtitles true/false] [Forced audio index 0-n] " +
 | 
			
		||||
@@ -274,6 +309,7 @@ class Main {
 | 
			
		||||
     * @param max <p>The number of tokens expected.</p>
 | 
			
		||||
     * @return <p>A list of tokens.</p>
 | 
			
		||||
     */
 | 
			
		||||
    @NotNull
 | 
			
		||||
    private static List<String> readInput(int max) {
 | 
			
		||||
        List<String> tokens = tokenize(READER.nextLine());
 | 
			
		||||
        if (max < tokens.size()) {
 | 
			
		||||
@@ -289,7 +325,8 @@ class Main {
 | 
			
		||||
     * @param prompt <p>The prompt shown to the user.</p>
 | 
			
		||||
     * @return <p>The non-empty choice given by the user.</p>
 | 
			
		||||
     */
 | 
			
		||||
    private static String getChoice(String prompt) {
 | 
			
		||||
    @NotNull
 | 
			
		||||
    private static String getChoice(@NotNull String prompt) {
 | 
			
		||||
        OutputUtil.println(prompt);
 | 
			
		||||
        String choice = "";
 | 
			
		||||
        while (choice.isEmpty()) {
 | 
			
		||||
@@ -307,7 +344,7 @@ class Main {
 | 
			
		||||
     * @param max    The maximum allowed value
 | 
			
		||||
     * @return The value given by the user
 | 
			
		||||
     */
 | 
			
		||||
    private static int getChoice(String prompt, int min, int max) {
 | 
			
		||||
    private static int getChoice(@NotNull String prompt, int min, int max) {
 | 
			
		||||
        OutputUtil.println(prompt);
 | 
			
		||||
        int choice = Integer.MIN_VALUE;
 | 
			
		||||
        do {
 | 
			
		||||
@@ -0,0 +1,92 @@
 | 
			
		||||
package net.knarcraft.ffmpegconverter.config;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.ffmpegconverter.utility.FileHelper;
 | 
			
		||||
import net.knarcraft.ffmpegconverter.utility.OutputUtil;
 | 
			
		||||
import org.apache.commons.configuration2.Configuration;
 | 
			
		||||
import org.apache.commons.configuration2.PropertiesConfiguration;
 | 
			
		||||
import org.apache.commons.configuration2.builder.FileBasedConfigurationBuilder;
 | 
			
		||||
import org.apache.commons.configuration2.builder.fluent.Configurations;
 | 
			
		||||
import org.apache.commons.configuration2.ex.ConfigurationException;
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
 | 
			
		||||
import java.io.BufferedReader;
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A handler for dealing with configurations
 | 
			
		||||
 */
 | 
			
		||||
public class ConfigHandler {
 | 
			
		||||
 | 
			
		||||
    private final File configFolder = new File("conf").getAbsoluteFile();
 | 
			
		||||
    private final Configurations configurations = new Configurations();
 | 
			
		||||
    private final File settingsFile = new File(configFolder, "config.properties");
 | 
			
		||||
    private FileBasedConfigurationBuilder<PropertiesConfiguration> builder = configurations.propertiesBuilder(settingsFile);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a writable configuration used for changing settings
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>A writable properties configuration</p>
 | 
			
		||||
     */
 | 
			
		||||
    @NotNull
 | 
			
		||||
    public PropertiesConfiguration getWritableConfiguration() {
 | 
			
		||||
        try {
 | 
			
		||||
            return builder.getConfiguration();
 | 
			
		||||
        } catch (ConfigurationException e) {
 | 
			
		||||
            throw new RuntimeException(e);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Writes the writable configuration to disk
 | 
			
		||||
     */
 | 
			
		||||
    public void writeConfiguration() {
 | 
			
		||||
        OutputUtil.printDebug("Preparing to save config");
 | 
			
		||||
        if (!configFolder.exists() && !configFolder.mkdir()) {
 | 
			
		||||
            throw new RuntimeException("Unable to create config folder. Make sure to run this .jar file from a " +
 | 
			
		||||
                    "writable directory!");
 | 
			
		||||
        }
 | 
			
		||||
        try {
 | 
			
		||||
            if (!settingsFile.exists() && !settingsFile.createNewFile()) {
 | 
			
		||||
                OutputUtil.println("Failed to create configuration file.");
 | 
			
		||||
            }
 | 
			
		||||
        } catch (IOException e) {
 | 
			
		||||
            OutputUtil.println("Failed to create configuration file.");
 | 
			
		||||
        }
 | 
			
		||||
        try {
 | 
			
		||||
            builder.save();
 | 
			
		||||
        } catch (ConfigurationException e) {
 | 
			
		||||
            throw new RuntimeException(e);
 | 
			
		||||
        }
 | 
			
		||||
        OutputUtil.printDebug("Saved available hardware encoder handler");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Loads the saved configuration file
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The loaded configuration</p>
 | 
			
		||||
     */
 | 
			
		||||
    @NotNull
 | 
			
		||||
    public Configuration load() throws IOException {
 | 
			
		||||
        Configuration configuration;
 | 
			
		||||
        if (!settingsFile.exists()) {
 | 
			
		||||
            configuration = new PropertiesConfiguration();
 | 
			
		||||
            BufferedReader reader = FileHelper.getBufferedReaderForInternalFile("/conf/config.properties");
 | 
			
		||||
            Map<String, String> entries = FileHelper.readKeyValuePairs(reader, "=");
 | 
			
		||||
            for (Map.Entry<String, String> entry : entries.entrySet()) {
 | 
			
		||||
                configuration.setProperty(entry.getKey(), entry.getValue());
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            try {
 | 
			
		||||
                configuration = configurations.properties(settingsFile);
 | 
			
		||||
            } catch (ConfigurationException e) {
 | 
			
		||||
                throw new RuntimeException(e);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        // Reload contents in the builder
 | 
			
		||||
        builder = configurations.propertiesBuilder(settingsFile);
 | 
			
		||||
        return configuration;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,12 +1,13 @@
 | 
			
		||||
package net.knarcraft.ffmpegconverter.converter;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.ffmpegconverter.FFMpegConvert;
 | 
			
		||||
import net.knarcraft.ffmpegconverter.container.FFMpegCommand;
 | 
			
		||||
import net.knarcraft.ffmpegconverter.container.StreamProbeResult;
 | 
			
		||||
import net.knarcraft.ffmpegconverter.handler.AvailableHardwareEncoderHandler;
 | 
			
		||||
import net.knarcraft.ffmpegconverter.utility.FFMpegHelper;
 | 
			
		||||
import net.knarcraft.ffmpegconverter.utility.FileHelper;
 | 
			
		||||
import net.knarcraft.ffmpegconverter.utility.FileUtil;
 | 
			
		||||
import net.knarcraft.ffmpegconverter.utility.OutputUtil;
 | 
			
		||||
import org.apache.commons.configuration2.ex.ConfigurationException;
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
import org.jetbrains.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
@@ -20,12 +21,13 @@ import java.util.List;
 | 
			
		||||
 */
 | 
			
		||||
public abstract class AbstractConverter implements Converter {
 | 
			
		||||
 | 
			
		||||
    final boolean debug = false;
 | 
			
		||||
    final boolean debug = FFMpegConvert.isDebugEnabled();
 | 
			
		||||
    private final String newExtension;
 | 
			
		||||
    protected String ffprobePath;
 | 
			
		||||
    protected String ffmpegPath;
 | 
			
		||||
    protected String[] audioFormats;
 | 
			
		||||
    protected String[] videoFormats;
 | 
			
		||||
    protected List<String> audioFormats;
 | 
			
		||||
    protected List<String> videoFormats;
 | 
			
		||||
    protected List<String> subtitleFormats;
 | 
			
		||||
    protected AvailableHardwareEncoderHandler encoderHandler = null;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -34,31 +36,31 @@ public abstract class AbstractConverter implements Converter {
 | 
			
		||||
     */
 | 
			
		||||
    AbstractConverter(@Nullable String newExtension) {
 | 
			
		||||
        this.newExtension = newExtension;
 | 
			
		||||
        OutputUtil.setDebug(this.debug);
 | 
			
		||||
        try {
 | 
			
		||||
            audioFormats = FileUtil.readFileLines("audio_formats.txt");
 | 
			
		||||
            videoFormats = FileUtil.readFileLines("video_formats.txt");
 | 
			
		||||
            this.audioFormats = FileHelper.readLines(FileHelper.getBufferedReaderForInternalFile("/audio_formats.txt"));
 | 
			
		||||
            this.videoFormats = FileHelper.readLines(FileHelper.getBufferedReaderForInternalFile("/video_formats.txt"));
 | 
			
		||||
            this.subtitleFormats = FileHelper.readLines(FileHelper.getBufferedReaderForInternalFile("/subtitle_formats.txt"));
 | 
			
		||||
        } catch (IOException e) {
 | 
			
		||||
            System.out.println("Unable to read audio and/or video formats from internal files.");
 | 
			
		||||
            OutputUtil.println("Unable to read audio and/or video formats from internal files.");
 | 
			
		||||
            System.exit(1);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void convert(@NotNull File file) throws IOException {
 | 
			
		||||
        StreamProbeResult probeResult = FFMpegHelper.probeFile(ffprobePath, file);
 | 
			
		||||
        StreamProbeResult probeResult = FFMpegHelper.probeFile(this.ffprobePath, file, this.subtitleFormats);
 | 
			
		||||
        if (probeResult.parsedStreams().isEmpty()) {
 | 
			
		||||
            throw new IllegalArgumentException("The file has no valid streams. Please make sure the file exists and" +
 | 
			
		||||
                    " is not corrupt.");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        String outExtension = newExtension != null ? newExtension : FileUtil.getExtension(file.getName());
 | 
			
		||||
        String outExtension = this.newExtension != null ? this.newExtension : FileUtil.getExtension(file.getName());
 | 
			
		||||
        String newPath = FileUtil.getNonCollidingPath(file.getParentFile(), file, outExtension);
 | 
			
		||||
        OutputUtil.println();
 | 
			
		||||
        OutputUtil.println("Preparing to start process...");
 | 
			
		||||
        OutputUtil.println("Converting " + file);
 | 
			
		||||
 | 
			
		||||
        FFMpegCommand ffMpegCommand = generateConversionCommand(ffmpegPath, probeResult, newPath);
 | 
			
		||||
        FFMpegCommand ffMpegCommand = generateConversionCommand(this.ffmpegPath, probeResult, newPath);
 | 
			
		||||
        // If the command is null, that means the file does not need conversion
 | 
			
		||||
        if (ffMpegCommand == null) {
 | 
			
		||||
            return;
 | 
			
		||||
@@ -73,11 +75,7 @@ public abstract class AbstractConverter implements Converter {
 | 
			
		||||
        ProcessBuilder processBuilder = new ProcessBuilder(command);
 | 
			
		||||
        int exitCode = FFMpegHelper.runProcess(processBuilder, file.getParentFile(), "\n", true).exitCode();
 | 
			
		||||
        if (exitCode != 0) {
 | 
			
		||||
            try {
 | 
			
		||||
                handleError(ffMpegCommand, file, newPath);
 | 
			
		||||
            } catch (ConfigurationException e) {
 | 
			
		||||
                throw new RuntimeException(e);
 | 
			
		||||
            }
 | 
			
		||||
            handleError(ffMpegCommand, file, newPath);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -87,11 +85,10 @@ public abstract class AbstractConverter implements Converter {
 | 
			
		||||
     * @param ffMpegCommand <p>The failed ffmpeg command</p>
 | 
			
		||||
     * @param file          <p>The file that was to be converted</p>
 | 
			
		||||
     * @param newPath       <p>The path of the output file</p>
 | 
			
		||||
     * @throws IOException            <p>If unable to produce output</p>
 | 
			
		||||
     * @throws ConfigurationException <p>If unable </p>
 | 
			
		||||
     * @throws IOException <p>If unable to produce output</p>
 | 
			
		||||
     */
 | 
			
		||||
    private void handleError(@NotNull FFMpegCommand ffMpegCommand, @NotNull File file,
 | 
			
		||||
                             @NotNull String newPath) throws IOException, ConfigurationException {
 | 
			
		||||
                             @NotNull String newPath) throws IOException {
 | 
			
		||||
        File outputFile = new File(newPath);
 | 
			
		||||
        if (outputFile.exists() && !outputFile.delete()) {
 | 
			
		||||
            OutputUtil.println("Failed to remove failed output file. Please remove it manually");
 | 
			
		||||
@@ -118,23 +115,24 @@ public abstract class AbstractConverter implements Converter {
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>Available hardware encoding methods</p>
 | 
			
		||||
     */
 | 
			
		||||
    @NotNull
 | 
			
		||||
    protected List<String> getAvailableHardwareEncodingMethods() {
 | 
			
		||||
        try {
 | 
			
		||||
            if (encoderHandler == null) {
 | 
			
		||||
                encoderHandler = AvailableHardwareEncoderHandler.load();
 | 
			
		||||
                if (encoderHandler.availableHardwareEncodings().isEmpty()) {
 | 
			
		||||
                    List<String> hardwareEncoding = new ArrayList<>(FFMpegHelper.getHWAcceleration(ffmpegPath));
 | 
			
		||||
                    hardwareEncoding.remove(0);
 | 
			
		||||
                    encoderHandler = new AvailableHardwareEncoderHandler(hardwareEncoding);
 | 
			
		||||
                    encoderHandler.save();
 | 
			
		||||
        if (encoderHandler == null) {
 | 
			
		||||
            encoderHandler = AvailableHardwareEncoderHandler.load();
 | 
			
		||||
            if (encoderHandler.availableHardwareEncodings().isEmpty()) {
 | 
			
		||||
                List<String> hardwareEncoding;
 | 
			
		||||
                try {
 | 
			
		||||
                    hardwareEncoding = new ArrayList<>(FFMpegHelper.getHWAcceleration(ffmpegPath));
 | 
			
		||||
                } catch (IOException e) {
 | 
			
		||||
                    throw new RuntimeException(e);
 | 
			
		||||
                }
 | 
			
		||||
                hardwareEncoding.remove(0);
 | 
			
		||||
                encoderHandler = new AvailableHardwareEncoderHandler(hardwareEncoding);
 | 
			
		||||
                encoderHandler.save();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return encoderHandler.availableHardwareEncodings();
 | 
			
		||||
        } catch (ConfigurationException | IOException exception) {
 | 
			
		||||
            OutputUtil.println("Unable to get available hardware encoders: " + exception.getMessage());
 | 
			
		||||
            return new ArrayList<>();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return encoderHandler.availableHardwareEncodings();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -26,6 +26,7 @@ import net.knarcraft.ffmpegconverter.streams.AudioStream;
 | 
			
		||||
import net.knarcraft.ffmpegconverter.streams.SubtitleStream;
 | 
			
		||||
import net.knarcraft.ffmpegconverter.utility.FFMpegHelper;
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
import org.jetbrains.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
@@ -69,6 +70,7 @@ public class AnimeConverter extends AbstractConverter {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    @Nullable
 | 
			
		||||
    public FFMpegCommand generateConversionCommand(@NotNull String executable,
 | 
			
		||||
                                                   @NotNull StreamProbeResult probeResult,
 | 
			
		||||
                                                   @NotNull String outFile) {
 | 
			
		||||
@@ -118,7 +120,8 @@ public class AnimeConverter extends AbstractConverter {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public @NotNull String[] getValidFormats() {
 | 
			
		||||
    @NotNull
 | 
			
		||||
    public List<String> getValidFormats() {
 | 
			
		||||
        return this.videoFormats;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,7 @@ import net.knarcraft.ffmpegconverter.converter.module.mapping.NthAudioStreamModu
 | 
			
		||||
import net.knarcraft.ffmpegconverter.converter.module.output.SetOutputFileModule;
 | 
			
		||||
import net.knarcraft.ffmpegconverter.utility.FFMpegHelper;
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
import org.jetbrains.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
@@ -25,13 +26,14 @@ public class AudioConverter extends AbstractConverter {
 | 
			
		||||
     * @param ffmpegPath   <p>Path/command to ffmpeg.</p>
 | 
			
		||||
     * @param newExtension <p>The extension of the new file.</p>
 | 
			
		||||
     */
 | 
			
		||||
    public AudioConverter(String ffprobePath, String ffmpegPath, String newExtension) {
 | 
			
		||||
    public AudioConverter(@NotNull String ffprobePath, @NotNull String ffmpegPath, @NotNull String newExtension) {
 | 
			
		||||
        super(newExtension);
 | 
			
		||||
        this.ffprobePath = ffprobePath;
 | 
			
		||||
        this.ffmpegPath = ffmpegPath;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    @Nullable
 | 
			
		||||
    public FFMpegCommand generateConversionCommand(@NotNull String executable, @NotNull StreamProbeResult probeResult,
 | 
			
		||||
                                                   @NotNull String outFile) {
 | 
			
		||||
        FFMpegCommand command = FFMpegHelper.getFFMpegGeneralFileCommand(executable, probeResult.parsedFiles());
 | 
			
		||||
@@ -50,7 +52,8 @@ public class AudioConverter extends AbstractConverter {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String[] getValidFormats() {
 | 
			
		||||
    @NotNull
 | 
			
		||||
    public List<String> getValidFormats() {
 | 
			
		||||
        return audioFormats;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -3,9 +3,11 @@ package net.knarcraft.ffmpegconverter.converter;
 | 
			
		||||
import net.knarcraft.ffmpegconverter.container.FFMpegCommand;
 | 
			
		||||
import net.knarcraft.ffmpegconverter.container.StreamProbeResult;
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
import org.jetbrains.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This interface describes a file converter
 | 
			
		||||
@@ -18,7 +20,7 @@ public interface Converter {
 | 
			
		||||
     * @return <p>A list of valid input formats</p>
 | 
			
		||||
     */
 | 
			
		||||
    @NotNull
 | 
			
		||||
    String[] getValidFormats();
 | 
			
		||||
    List<String> getValidFormats();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Converts the given file
 | 
			
		||||
@@ -36,6 +38,7 @@ public interface Converter {
 | 
			
		||||
     * @param outFile     <p>The output file</p>
 | 
			
		||||
     * @return <p>A list of commands</p>
 | 
			
		||||
     */
 | 
			
		||||
    @Nullable
 | 
			
		||||
    FFMpegCommand generateConversionCommand(@NotNull String executable, @NotNull StreamProbeResult probeResult,
 | 
			
		||||
                                            @NotNull String outFile);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -16,6 +16,7 @@ import net.knarcraft.ffmpegconverter.streams.StreamObject;
 | 
			
		||||
import net.knarcraft.ffmpegconverter.streams.VideoStream;
 | 
			
		||||
import net.knarcraft.ffmpegconverter.utility.FFMpegHelper;
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
import org.jetbrains.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
@@ -36,7 +37,7 @@ public class DownScaleConverter extends AbstractConverter {
 | 
			
		||||
     * @param newWidth    <p>The new width of the video</p>
 | 
			
		||||
     * @param newHeight   <p>The new height of the video</p>
 | 
			
		||||
     */
 | 
			
		||||
    public DownScaleConverter(String ffprobePath, String ffmpegPath, int newWidth, int newHeight) {
 | 
			
		||||
    public DownScaleConverter(@NotNull String ffprobePath, @NotNull String ffmpegPath, int newWidth, int newHeight) {
 | 
			
		||||
        super(null);
 | 
			
		||||
        this.ffprobePath = ffprobePath;
 | 
			
		||||
        this.ffmpegPath = ffmpegPath;
 | 
			
		||||
@@ -45,6 +46,7 @@ public class DownScaleConverter extends AbstractConverter {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    @Nullable
 | 
			
		||||
    public FFMpegCommand generateConversionCommand(@NotNull String executable, @NotNull StreamProbeResult probeResult,
 | 
			
		||||
                                                   @NotNull String outFile) {
 | 
			
		||||
        List<StreamObject> streams = probeResult.parsedStreams();
 | 
			
		||||
@@ -78,7 +80,8 @@ public class DownScaleConverter extends AbstractConverter {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String[] getValidFormats() {
 | 
			
		||||
    @NotNull
 | 
			
		||||
    public List<String> getValidFormats() {
 | 
			
		||||
        return videoFormats;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -13,6 +13,7 @@ import net.knarcraft.ffmpegconverter.converter.module.output.CopyAllModule;
 | 
			
		||||
import net.knarcraft.ffmpegconverter.converter.module.output.SetOutputFileModule;
 | 
			
		||||
import net.knarcraft.ffmpegconverter.utility.FFMpegHelper;
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
import org.jetbrains.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
@@ -46,11 +47,13 @@ public class MKVToMP4Transcoder extends AbstractConverter {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String[] getValidFormats() {
 | 
			
		||||
        return new String[]{"mkv"};
 | 
			
		||||
    @NotNull
 | 
			
		||||
    public List<String> getValidFormats() {
 | 
			
		||||
        return List.of("mkv");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    @Nullable
 | 
			
		||||
    public FFMpegCommand generateConversionCommand(@NotNull String executable, @NotNull StreamProbeResult probeResult,
 | 
			
		||||
                                                   @NotNull String outFile) {
 | 
			
		||||
        FFMpegCommand command = FFMpegHelper.getFFMpegGeneralFileCommand(executable, probeResult.parsedFiles());
 | 
			
		||||
 
 | 
			
		||||
@@ -15,6 +15,7 @@ import net.knarcraft.ffmpegconverter.converter.module.output.SetOutputFileModule
 | 
			
		||||
import net.knarcraft.ffmpegconverter.streams.StreamObject;
 | 
			
		||||
import net.knarcraft.ffmpegconverter.utility.FFMpegHelper;
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
import org.jetbrains.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
@@ -37,11 +38,13 @@ public class MkvH264Converter extends AbstractConverter {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String[] getValidFormats() {
 | 
			
		||||
        return new String[]{"mkv"};
 | 
			
		||||
    @NotNull
 | 
			
		||||
    public List<String> getValidFormats() {
 | 
			
		||||
        return List.of("mkv");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    @Nullable
 | 
			
		||||
    public FFMpegCommand generateConversionCommand(@NotNull String executable, @NotNull StreamProbeResult probeResult,
 | 
			
		||||
                                                   @NotNull String outFile) {
 | 
			
		||||
        FFMpegCommand command = FFMpegHelper.getFFMpegGeneralFileCommand(executable, probeResult.parsedFiles());
 | 
			
		||||
 
 | 
			
		||||
@@ -16,6 +16,7 @@ import net.knarcraft.ffmpegconverter.streams.SubtitleStream;
 | 
			
		||||
import net.knarcraft.ffmpegconverter.streams.VideoStream;
 | 
			
		||||
import net.knarcraft.ffmpegconverter.utility.FFMpegHelper;
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
import org.jetbrains.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
@@ -38,11 +39,13 @@ public class MkvH265ReducedConverter extends AbstractConverter {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String[] getValidFormats() {
 | 
			
		||||
        return new String[]{"mkv"};
 | 
			
		||||
    @NotNull
 | 
			
		||||
    public List<String> getValidFormats() {
 | 
			
		||||
        return List.of("mkv");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    @Nullable
 | 
			
		||||
    public FFMpegCommand generateConversionCommand(@NotNull String executable, @NotNull StreamProbeResult probeResult,
 | 
			
		||||
                                                   @NotNull String outFile) {
 | 
			
		||||
        FFMpegCommand command = FFMpegHelper.getFFMpegGeneralFileCommand(executable, probeResult.parsedFiles());
 | 
			
		||||
 
 | 
			
		||||
@@ -12,6 +12,7 @@ import net.knarcraft.ffmpegconverter.converter.module.output.MovTextModule;
 | 
			
		||||
import net.knarcraft.ffmpegconverter.converter.module.output.SetOutputFileModule;
 | 
			
		||||
import net.knarcraft.ffmpegconverter.utility.FFMpegHelper;
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
import org.jetbrains.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
@@ -34,11 +35,13 @@ public class SubtitleEmbed extends AbstractConverter {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String[] getValidFormats() {
 | 
			
		||||
        return new String[]{"mp4"};
 | 
			
		||||
    @NotNull
 | 
			
		||||
    public List<String> getValidFormats() {
 | 
			
		||||
        return List.of("mp4");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    @Nullable
 | 
			
		||||
    public FFMpegCommand generateConversionCommand(@NotNull String executable, @NotNull StreamProbeResult probeResult,
 | 
			
		||||
                                                   @NotNull String outFile) {
 | 
			
		||||
        FFMpegCommand command = FFMpegHelper.getFFMpegGeneralFileCommand(executable, probeResult.parsedFiles());
 | 
			
		||||
 
 | 
			
		||||
@@ -12,6 +12,7 @@ import net.knarcraft.ffmpegconverter.converter.module.output.SetOutputFileModule
 | 
			
		||||
import net.knarcraft.ffmpegconverter.streams.StreamObject;
 | 
			
		||||
import net.knarcraft.ffmpegconverter.utility.FFMpegHelper;
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
import org.jetbrains.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
@@ -35,6 +36,7 @@ public class VideoConverter extends AbstractConverter {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    @Nullable
 | 
			
		||||
    public FFMpegCommand generateConversionCommand(@NotNull String executable, @NotNull StreamProbeResult probeResult,
 | 
			
		||||
                                                   @NotNull String outFile) {
 | 
			
		||||
        FFMpegCommand command = FFMpegHelper.getFFMpegGeneralFileCommand(executable, probeResult.parsedFiles());
 | 
			
		||||
@@ -57,7 +59,8 @@ public class VideoConverter extends AbstractConverter {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String[] getValidFormats() {
 | 
			
		||||
    @NotNull
 | 
			
		||||
    public List<String> getValidFormats() {
 | 
			
		||||
        return videoFormats;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -21,6 +21,7 @@ import net.knarcraft.ffmpegconverter.streams.SubtitleStream;
 | 
			
		||||
import net.knarcraft.ffmpegconverter.streams.VideoStream;
 | 
			
		||||
import net.knarcraft.ffmpegconverter.utility.FFMpegHelper;
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
import org.jetbrains.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
@@ -69,6 +70,7 @@ public class WebAnimeConverter extends AbstractConverter {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    @Nullable
 | 
			
		||||
    public FFMpegCommand generateConversionCommand(@NotNull String executable, @NotNull StreamProbeResult probeResult,
 | 
			
		||||
                                                   @NotNull String outFile) {
 | 
			
		||||
        FFMpegCommand command = FFMpegHelper.getFFMpegWebVideoCommand(executable, probeResult.parsedFiles());
 | 
			
		||||
@@ -114,7 +116,8 @@ public class WebAnimeConverter extends AbstractConverter {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String[] getValidFormats() {
 | 
			
		||||
    @NotNull
 | 
			
		||||
    public List<String> getValidFormats() {
 | 
			
		||||
        return this.videoFormats;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -14,6 +14,7 @@ import net.knarcraft.ffmpegconverter.streams.SubtitleStream;
 | 
			
		||||
import net.knarcraft.ffmpegconverter.streams.VideoStream;
 | 
			
		||||
import net.knarcraft.ffmpegconverter.utility.FFMpegHelper;
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
import org.jetbrains.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
@@ -39,11 +40,13 @@ public class WebVideoConverter extends AbstractConverter {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String[] getValidFormats() {
 | 
			
		||||
    @NotNull
 | 
			
		||||
    public List<String> getValidFormats() {
 | 
			
		||||
        return videoFormats;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    @Nullable
 | 
			
		||||
    public FFMpegCommand generateConversionCommand(@NotNull String executable, @NotNull StreamProbeResult probeResult,
 | 
			
		||||
                                                   @NotNull String outFile) {
 | 
			
		||||
        FFMpegCommand command = FFMpegHelper.getFFMpegWebVideoCommand(executable, probeResult.parsedFiles());
 | 
			
		||||
 
 | 
			
		||||
@@ -1,14 +1,12 @@
 | 
			
		||||
package net.knarcraft.ffmpegconverter.handler;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.ffmpegconverter.FFMpegConvert;
 | 
			
		||||
import net.knarcraft.ffmpegconverter.config.ConfigHandler;
 | 
			
		||||
import net.knarcraft.ffmpegconverter.utility.OutputUtil;
 | 
			
		||||
import org.apache.commons.configuration2.Configuration;
 | 
			
		||||
import org.apache.commons.configuration2.PropertiesConfiguration;
 | 
			
		||||
import org.apache.commons.configuration2.builder.FileBasedConfigurationBuilder;
 | 
			
		||||
import org.apache.commons.configuration2.builder.fluent.Configurations;
 | 
			
		||||
import org.apache.commons.configuration2.ex.ConfigurationException;
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
@@ -18,8 +16,7 @@ import java.util.List;
 | 
			
		||||
 */
 | 
			
		||||
public record AvailableHardwareEncoderHandler(@NotNull List<String> availableHardwareEncodings) {
 | 
			
		||||
 | 
			
		||||
    private static final File configFolder = new File("conf").getAbsoluteFile();
 | 
			
		||||
    private static final Configurations configurations = new Configurations();
 | 
			
		||||
    private static final ConfigHandler configHandler = FFMpegConvert.getConfigHandler();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets all hardware encodings
 | 
			
		||||
@@ -42,30 +39,12 @@ public record AvailableHardwareEncoderHandler(@NotNull List<String> availableHar
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Saves settings fro this available hardware encoder handler
 | 
			
		||||
     *
 | 
			
		||||
     * @throws ConfigurationException <p>If the configuration file cannot be saved</p>
 | 
			
		||||
     * Saves settings for this available hardware encoder handler
 | 
			
		||||
     */
 | 
			
		||||
    public void save() throws ConfigurationException {
 | 
			
		||||
        OutputUtil.printDebug("Preparing to save config");
 | 
			
		||||
        if (!configFolder.exists() && !configFolder.mkdir()) {
 | 
			
		||||
            throw new RuntimeException("Unable to create config folder. Make sure to run this .jar file from a " +
 | 
			
		||||
                    "writable directory!");
 | 
			
		||||
        }
 | 
			
		||||
        File settingsFile = new File(configFolder, "config.properties");
 | 
			
		||||
        try {
 | 
			
		||||
            if (!settingsFile.exists() && !settingsFile.createNewFile()) {
 | 
			
		||||
                OutputUtil.println("Failed to create configuration file.");
 | 
			
		||||
            }
 | 
			
		||||
        } catch (IOException e) {
 | 
			
		||||
            OutputUtil.println("Failed to create configuration file.");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        FileBasedConfigurationBuilder<PropertiesConfiguration> builder =
 | 
			
		||||
                configurations.propertiesBuilder(settingsFile);
 | 
			
		||||
        PropertiesConfiguration config = builder.getConfiguration();
 | 
			
		||||
        config.setProperty("encoder.hardware", this.availableHardwareEncodings);
 | 
			
		||||
        builder.save();
 | 
			
		||||
    public void save() {
 | 
			
		||||
        PropertiesConfiguration configuration = configHandler.getWritableConfiguration();
 | 
			
		||||
        configuration.setProperty("encoder.hardware", this.availableHardwareEncodings);
 | 
			
		||||
        configHandler.writeConfiguration();
 | 
			
		||||
        OutputUtil.printDebug("Saved available hardware encoder handler");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -73,14 +52,15 @@ public record AvailableHardwareEncoderHandler(@NotNull List<String> availableHar
 | 
			
		||||
     * Loads saved settings for an available hardware encoder handler
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The loaded available hardware encoder handler, or a new one if no data has been saved</p>
 | 
			
		||||
     * @throws ConfigurationException <p>If the configuration file cannot be loaded</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static AvailableHardwareEncoderHandler load() throws ConfigurationException {
 | 
			
		||||
        File settingsFile = new File(configFolder, "config.properties");
 | 
			
		||||
        if (!settingsFile.exists()) {
 | 
			
		||||
            return new AvailableHardwareEncoderHandler(new ArrayList<>());
 | 
			
		||||
    @NotNull
 | 
			
		||||
    public static AvailableHardwareEncoderHandler load() {
 | 
			
		||||
        Configuration configuration;
 | 
			
		||||
        try {
 | 
			
		||||
            configuration = configHandler.load();
 | 
			
		||||
        } catch (IOException e) {
 | 
			
		||||
            throw new RuntimeException(e);
 | 
			
		||||
        }
 | 
			
		||||
        Configuration configuration = configurations.properties(settingsFile);
 | 
			
		||||
        List<String> getEncodings = configuration.getList(String.class, "encoder.hardware");
 | 
			
		||||
        return new AvailableHardwareEncoderHandler(getEncodings);
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
package net.knarcraft.ffmpegconverter.parser;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.ffmpegconverter.utility.ListUtil;
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A class representing a command argument
 | 
			
		||||
@@ -20,7 +21,8 @@ public class ConverterArgument {
 | 
			
		||||
     * @param valueRequired <p>Whether the argument must be followed by a valid value.</p>
 | 
			
		||||
     * @param valueType     <p>The type of value the argument requires.</p>
 | 
			
		||||
     */
 | 
			
		||||
    public ConverterArgument(String name, char shorthand, boolean valueRequired, ConverterArgumentValueType valueType) {
 | 
			
		||||
    public ConverterArgument(@NotNull String name, char shorthand, boolean valueRequired,
 | 
			
		||||
                             @NotNull ConverterArgumentValueType valueType) {
 | 
			
		||||
        this.name = name;
 | 
			
		||||
        this.shorthand = shorthand;
 | 
			
		||||
        this.valueRequired = valueRequired;
 | 
			
		||||
@@ -60,7 +62,7 @@ public class ConverterArgument {
 | 
			
		||||
     * @param value <p>The value to test.</p>
 | 
			
		||||
     * @return <p>True if the argument is valid. False otherwise.</p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean testArgumentValue(String value) {
 | 
			
		||||
    public boolean testArgumentValue(@NotNull String value) {
 | 
			
		||||
        if (value.isEmpty()) {
 | 
			
		||||
            return !valueRequired;
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -36,7 +36,8 @@ public abstract class AbstractStream implements StreamObject {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public @NotNull String getCodecName() {
 | 
			
		||||
    @NotNull
 | 
			
		||||
    public String getCodecName() {
 | 
			
		||||
        return this.codecName;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -51,7 +52,8 @@ public abstract class AbstractStream implements StreamObject {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public @NotNull String getLanguage() {
 | 
			
		||||
    @NotNull
 | 
			
		||||
    public String getLanguage() {
 | 
			
		||||
        return this.language;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -27,7 +27,6 @@ import java.util.Map;
 | 
			
		||||
public final class FFMpegHelper {
 | 
			
		||||
 | 
			
		||||
    private static final String PROBE_SPLIT_CHARACTER = "øæåÆØå";
 | 
			
		||||
    private static String[] subtitleFormats = null;
 | 
			
		||||
 | 
			
		||||
    private FFMpegHelper() {
 | 
			
		||||
 | 
			
		||||
@@ -70,14 +69,16 @@ public final class FFMpegHelper {
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets streams from a file
 | 
			
		||||
     *
 | 
			
		||||
     * @param ffprobePath <p>The path/command to ffprobe.</p>
 | 
			
		||||
     * @param file        <p>The file to probe.</p>
 | 
			
		||||
     * @return <p>A list of StreamObjects.</p>
 | 
			
		||||
     * @throws IOException <p>If the process can't be readProcess.</p>
 | 
			
		||||
     * @param ffprobePath     <p>The path/command to ffprobe</p>
 | 
			
		||||
     * @param file            <p>The file to probe</p>
 | 
			
		||||
     * @param subtitleFormats <p>The extensions to accept for external subtitles</p>
 | 
			
		||||
     * @return <p>A list of StreamObjects</p>
 | 
			
		||||
     * @throws IOException <p>If the process can't be readProcess</p>
 | 
			
		||||
     */
 | 
			
		||||
    @NotNull
 | 
			
		||||
    public static StreamProbeResult probeFile(@NotNull String ffprobePath, @NotNull File file) throws IOException {
 | 
			
		||||
        return parseStreams(ffprobePath, probeForStreams(ffprobePath, file), file);
 | 
			
		||||
    public static StreamProbeResult probeFile(@NotNull String ffprobePath, @NotNull File file,
 | 
			
		||||
                                              @NotNull List<String> subtitleFormats) throws IOException {
 | 
			
		||||
        return parseStreams(ffprobePath, probeForStreams(ffprobePath, file), file, subtitleFormats);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -223,7 +224,8 @@ public final class FFMpegHelper {
 | 
			
		||||
     * @param fileName <p>The filename to escape.</p>
 | 
			
		||||
     * @return <p>A filename with known special characters escaped.</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static String escapeSpecialCharactersInFileName(String fileName) {
 | 
			
		||||
    @NotNull
 | 
			
		||||
    public static String escapeSpecialCharactersInFileName(@NotNull String fileName) {
 | 
			
		||||
        return fileName.replaceAll("\\\\", "\\\\\\\\\\\\\\\\")
 | 
			
		||||
                .replaceAll("'", "'\\\\\\\\\\\\\''")
 | 
			
		||||
                .replaceAll("%", "\\\\\\\\\\\\%")
 | 
			
		||||
@@ -260,7 +262,8 @@ public final class FFMpegHelper {
 | 
			
		||||
     * @return <p>A list of streams.</p>
 | 
			
		||||
     * @throws IOException <p>If something goes wrong while probing.</p>
 | 
			
		||||
     */
 | 
			
		||||
    private static List<String> probeForStreams(String ffprobePath, File file) throws IOException {
 | 
			
		||||
    @NotNull
 | 
			
		||||
    private static List<String> probeForStreams(@NotNull String ffprobePath, @NotNull File file) throws IOException {
 | 
			
		||||
        FFMpegCommand probeCommand = new FFMpegCommand(ffprobePath);
 | 
			
		||||
        probeCommand.addGlobalOption("-v", "error", "-show_streams");
 | 
			
		||||
        probeCommand.addInputFile(file.toString());
 | 
			
		||||
@@ -276,13 +279,15 @@ public final class FFMpegHelper {
 | 
			
		||||
    /**
 | 
			
		||||
     * Takes a list of all streams and parses each stream into one of three objects
 | 
			
		||||
     *
 | 
			
		||||
     * @param streams <p>A list of all streams for the current file.</p>
 | 
			
		||||
     * @param file    <p>The file currently being converted.</p>
 | 
			
		||||
     * @param ffprobePath     <p>The path to the ffprobe executable</p>
 | 
			
		||||
     * @param streams         <p>A list of all streams for the current file.</p>
 | 
			
		||||
     * @param file            <p>The file currently being converted.</p>
 | 
			
		||||
     * @param subtitleFormats <p>The extensions to accept for external subtitles</p>
 | 
			
		||||
     * @return <p>A list of StreamObjects.</p>
 | 
			
		||||
     */
 | 
			
		||||
    @NotNull
 | 
			
		||||
    private static StreamProbeResult parseStreams(@NotNull String ffprobePath, @NotNull List<String> streams,
 | 
			
		||||
                                                  @NotNull File file) throws IOException {
 | 
			
		||||
                                                  @NotNull File file, @NotNull List<String> subtitleFormats) throws IOException {
 | 
			
		||||
        List<StreamObject> parsedStreams = new ArrayList<>();
 | 
			
		||||
        int relativeAudioIndex = 0;
 | 
			
		||||
        int relativeVideoIndex = 0;
 | 
			
		||||
@@ -306,7 +311,7 @@ public final class FFMpegHelper {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        StreamProbeResult probeResult = new StreamProbeResult(List.of(file), parsedStreams);
 | 
			
		||||
        getExternalSubtitles(probeResult, ffprobePath, file.getParentFile(), file.getName());
 | 
			
		||||
        getExternalSubtitles(probeResult, ffprobePath, file.getParentFile(), file.getName(), subtitleFormats);
 | 
			
		||||
        return probeResult;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -335,17 +340,16 @@ public final class FFMpegHelper {
 | 
			
		||||
    /**
 | 
			
		||||
     * Tries to find any external subtitles adjacent to the first input file, and appends it to the given probe result
 | 
			
		||||
     *
 | 
			
		||||
     * @param ffprobePath    <p>The path/command to ffprobe</p>
 | 
			
		||||
     * @param directory      <p>The directory containing the file</p>
 | 
			
		||||
     * @param convertingFile <p>The first/main file to be converted</p>
 | 
			
		||||
     * @param streamProbeResult <p>The stream probe result to append to</p>
 | 
			
		||||
     * @param ffprobePath       <p>The path/command to ffprobe</p>
 | 
			
		||||
     * @param directory         <p>The directory containing the file</p>
 | 
			
		||||
     * @param convertingFile    <p>The first/main file to be converted</p>
 | 
			
		||||
     * @param subtitleFormats   <p>The extensions to accept for external subtitles</p>
 | 
			
		||||
     */
 | 
			
		||||
    private static void getExternalSubtitles(@NotNull StreamProbeResult streamProbeResult,
 | 
			
		||||
                                             @NotNull String ffprobePath, @NotNull File directory,
 | 
			
		||||
                                             @NotNull String convertingFile) throws IOException {
 | 
			
		||||
                                             @NotNull String convertingFile, @NotNull List<String> subtitleFormats) throws IOException {
 | 
			
		||||
        //Find all files in the same directory with external subtitle formats
 | 
			
		||||
        if (subtitleFormats == null) {
 | 
			
		||||
            subtitleFormats = FileUtil.readFileLines("subtitle_formats.txt");
 | 
			
		||||
        }
 | 
			
		||||
        File[] subtitleFiles = FileUtil.listFilesRecursive(directory, subtitleFormats, 1);
 | 
			
		||||
        // TODO: Generalize this for external audio tracks
 | 
			
		||||
 | 
			
		||||
@@ -382,7 +386,8 @@ public final class FFMpegHelper {
 | 
			
		||||
     * @return <p>The output from the readProcess.</p>
 | 
			
		||||
     * @throws IOException <p>On reader failure.</p>
 | 
			
		||||
     */
 | 
			
		||||
    private static String readProcess(BufferedReader reader, String spacer) throws IOException {
 | 
			
		||||
    @NotNull
 | 
			
		||||
    private static String readProcess(@NotNull BufferedReader reader, @NotNull String spacer) throws IOException {
 | 
			
		||||
        String line;
 | 
			
		||||
        StringBuilder text = new StringBuilder();
 | 
			
		||||
        while (reader.ready() && (line = reader.readLine()) != null && !line.isEmpty() && !line.equals("\n")) {
 | 
			
		||||
@@ -398,6 +403,7 @@ public final class FFMpegHelper {
 | 
			
		||||
     * @return <p>The available hardware acceleration methods</p>
 | 
			
		||||
     * @throws IOException <p>If the process fails</p>
 | 
			
		||||
     */
 | 
			
		||||
    @NotNull
 | 
			
		||||
    public static List<String> getHWAcceleration(@NotNull String ffmpegPath) throws IOException {
 | 
			
		||||
        FFMpegCommand probeCommand = new FFMpegCommand(ffmpegPath);
 | 
			
		||||
        probeCommand.addGlobalOption("-v", "error", "-hwaccels");
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,178 @@
 | 
			
		||||
package net.knarcraft.ffmpegconverter.utility;
 | 
			
		||||
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
import org.jetbrains.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import java.io.BufferedReader;
 | 
			
		||||
import java.io.BufferedWriter;
 | 
			
		||||
import java.io.FileInputStream;
 | 
			
		||||
import java.io.FileNotFoundException;
 | 
			
		||||
import java.io.FileOutputStream;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.io.InputStream;
 | 
			
		||||
import java.io.InputStreamReader;
 | 
			
		||||
import java.io.OutputStreamWriter;
 | 
			
		||||
import java.nio.charset.StandardCharsets;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A helper class for dealing with files
 | 
			
		||||
 */
 | 
			
		||||
@SuppressWarnings("unused")
 | 
			
		||||
public final class FileHelper {
 | 
			
		||||
 | 
			
		||||
    private FileHelper() {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a buffered reader for an internal file
 | 
			
		||||
     *
 | 
			
		||||
     * @param file <p>The name of the file to get a buffered reader for (start with a '/'). The file should reside in
 | 
			
		||||
     *             the resources directory.</p>
 | 
			
		||||
     * @return <p>A buffered read for reading the file</p>
 | 
			
		||||
     * @throws FileNotFoundException <p>If unable to get an input stream for the given file</p>
 | 
			
		||||
     */
 | 
			
		||||
    @NotNull
 | 
			
		||||
    public static BufferedReader getBufferedReaderForInternalFile(@NotNull String file) throws FileNotFoundException {
 | 
			
		||||
        InputStream inputStream = getInputStreamForInternalFile(file);
 | 
			
		||||
        if (inputStream == null) {
 | 
			
		||||
            throw new FileNotFoundException("Unable to read the given file");
 | 
			
		||||
        }
 | 
			
		||||
        return getBufferedReaderFromInputStream(inputStream);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets an input stream from a string pointing to an internal file
 | 
			
		||||
     *
 | 
			
		||||
     * <p>This is used for getting an input stream for reading a file contained within the compiled .jar file. The file
 | 
			
		||||
     * should be in the resources directory, and the file path should start with a forward slash ("/") character.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @param file <p>The file to read</p>
 | 
			
		||||
     * @return <p>An input stream for the file</p>
 | 
			
		||||
     */
 | 
			
		||||
    @Nullable
 | 
			
		||||
    public static InputStream getInputStreamForInternalFile(@NotNull String file) {
 | 
			
		||||
        return FileHelper.class.getResourceAsStream(file);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a buffered reader from a string pointing to a file
 | 
			
		||||
     *
 | 
			
		||||
     * @param file <p>The file to read</p>
 | 
			
		||||
     * @return <p>A buffered reader reading the file</p>
 | 
			
		||||
     * @throws FileNotFoundException <p>If the given file does not exist</p>
 | 
			
		||||
     */
 | 
			
		||||
    @NotNull
 | 
			
		||||
 | 
			
		||||
    public static BufferedReader getBufferedReaderFromString(@NotNull String file) throws FileNotFoundException {
 | 
			
		||||
        FileInputStream fileInputStream = new FileInputStream(file);
 | 
			
		||||
        return getBufferedReaderFromInputStream(fileInputStream);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a buffered reader given an input stream
 | 
			
		||||
     *
 | 
			
		||||
     * @param inputStream <p>The input stream to read</p>
 | 
			
		||||
     * @return <p>A buffered reader reading the input stream</p>
 | 
			
		||||
     */
 | 
			
		||||
    @NotNull
 | 
			
		||||
    public static BufferedReader getBufferedReaderFromInputStream(@NotNull InputStream inputStream) {
 | 
			
		||||
        InputStreamReader inputStreamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
 | 
			
		||||
        return new BufferedReader(inputStreamReader);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a buffered writer from a string pointing to a file
 | 
			
		||||
     *
 | 
			
		||||
     * @param file <p>The file to write to</p>
 | 
			
		||||
     * @return <p>A buffered writer writing to the file</p>
 | 
			
		||||
     * @throws FileNotFoundException <p>If the file does not exist</p>
 | 
			
		||||
     */
 | 
			
		||||
    @NotNull
 | 
			
		||||
    public static BufferedWriter getBufferedWriterFromString(@NotNull String file) throws FileNotFoundException {
 | 
			
		||||
        FileOutputStream fileOutputStream = new FileOutputStream(file);
 | 
			
		||||
        OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream, StandardCharsets.UTF_8);
 | 
			
		||||
        return new BufferedWriter(outputStreamWriter);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Reads key/value pairs from a buffered reader
 | 
			
		||||
     *
 | 
			
		||||
     * @param bufferedReader <p>The buffered reader to read</p>
 | 
			
		||||
     * @param separator      <p>The separator separating a key from a value</p>
 | 
			
		||||
     * @return <p>A map containing the read pairs</p>
 | 
			
		||||
     * @throws IOException <p>If unable to read from the stream</p>
 | 
			
		||||
     */
 | 
			
		||||
    @NotNull
 | 
			
		||||
    public static Map<String, String> readKeyValuePairs(@NotNull BufferedReader bufferedReader,
 | 
			
		||||
                                                        @NotNull String separator) throws IOException {
 | 
			
		||||
        Map<String, String> readPairs = new HashMap<>();
 | 
			
		||||
        List<String> lines = readLines(bufferedReader);
 | 
			
		||||
 | 
			
		||||
        for (String line : lines) {
 | 
			
		||||
            int separatorIndex = line.indexOf(separator);
 | 
			
		||||
            if (separatorIndex == -1) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            //Read the line
 | 
			
		||||
            String key = line.substring(0, separatorIndex);
 | 
			
		||||
            String value = line.substring(separatorIndex + 1);
 | 
			
		||||
            readPairs.put(key, value);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return readPairs;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Reads a list from a buffered reader
 | 
			
		||||
     *
 | 
			
		||||
     * @param bufferedReader <p>The buffered reader to read</p>
 | 
			
		||||
     * @return <p>A list of the read strings</p>
 | 
			
		||||
     * @throws IOException <p>If unable to read from the stream</p>
 | 
			
		||||
     */
 | 
			
		||||
    @NotNull
 | 
			
		||||
    public static List<String> readLines(@NotNull BufferedReader bufferedReader) throws IOException {
 | 
			
		||||
        List<String> readLines = new ArrayList<>();
 | 
			
		||||
 | 
			
		||||
        String line = bufferedReader.readLine();
 | 
			
		||||
        boolean firstLine = true;
 | 
			
		||||
        while (line != null) {
 | 
			
		||||
            //Strip UTF BOM from the first line
 | 
			
		||||
            if (firstLine) {
 | 
			
		||||
                line = removeUTF8BOM(line);
 | 
			
		||||
                firstLine = false;
 | 
			
		||||
            }
 | 
			
		||||
            //Split at first separator
 | 
			
		||||
            if (line.isEmpty()) {
 | 
			
		||||
                line = bufferedReader.readLine();
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            readLines.add(line);
 | 
			
		||||
            line = bufferedReader.readLine();
 | 
			
		||||
        }
 | 
			
		||||
        bufferedReader.close();
 | 
			
		||||
 | 
			
		||||
        return readLines;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Removes the UTF-8 Byte Order Mark if present
 | 
			
		||||
     *
 | 
			
		||||
     * @param string <p>The string to remove the BOM from</p>
 | 
			
		||||
     * @return <p>A string guaranteed without a BOM</p>
 | 
			
		||||
     */
 | 
			
		||||
    private static @NotNull String removeUTF8BOM(@NotNull String string) {
 | 
			
		||||
        String UTF8_BOM = "\uFEFF";
 | 
			
		||||
        if (string.startsWith(UTF8_BOM)) {
 | 
			
		||||
            string = string.substring(1);
 | 
			
		||||
        }
 | 
			
		||||
        return string;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,10 +1,10 @@
 | 
			
		||||
package net.knarcraft.ffmpegconverter.utility;
 | 
			
		||||
 | 
			
		||||
import java.io.BufferedReader;
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
import org.jetbrains.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.io.InputStream;
 | 
			
		||||
import java.io.InputStreamReader;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A class which helps with file handling
 | 
			
		||||
@@ -23,7 +23,8 @@ public final class FileUtil {
 | 
			
		||||
     * @param outExtension <p>The extension of the output file.</p>
 | 
			
		||||
     * @return <p>A file name with the new extension and without any collisions.</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static String getNonCollidingPath(File folder, File file, String outExtension) {
 | 
			
		||||
    @NotNull
 | 
			
		||||
    public static String getNonCollidingPath(@NotNull File folder, @NotNull File file, @NotNull String outExtension) {
 | 
			
		||||
        return FileUtil.getNonCollidingFilename(folder.getAbsolutePath() + File.separator +
 | 
			
		||||
                FileUtil.stripExtension(file.getName()) + "." + outExtension, outExtension);
 | 
			
		||||
    }
 | 
			
		||||
@@ -35,7 +36,8 @@ public final class FileUtil {
 | 
			
		||||
     * @param maxRecursions <p>Maximum number of recursions</p>
 | 
			
		||||
     * @return A list of files
 | 
			
		||||
     */
 | 
			
		||||
    public static File[] listFilesRecursive(File folder, String[] extensions, int maxRecursions) {
 | 
			
		||||
    @Nullable
 | 
			
		||||
    public static File[] listFilesRecursive(@NotNull File folder, @NotNull List<String> extensions, int maxRecursions) {
 | 
			
		||||
        //Return if the target depth has been reached
 | 
			
		||||
        if (maxRecursions == 0) {
 | 
			
		||||
            return null;
 | 
			
		||||
@@ -43,6 +45,7 @@ public final class FileUtil {
 | 
			
		||||
        //Get a list of all files which are folders and has one of the extensions specified
 | 
			
		||||
        File[] foundFiles = folder.listFiles((file) -> file.isFile() &&
 | 
			
		||||
                ListUtil.listContains(extensions, (item) -> file.getName().toLowerCase().endsWith(item)));
 | 
			
		||||
 | 
			
		||||
        //Return if recursion is finished
 | 
			
		||||
        if (maxRecursions == 1) {
 | 
			
		||||
            return foundFiles;
 | 
			
		||||
@@ -68,36 +71,6 @@ public final class FileUtil {
 | 
			
		||||
        return foundFiles;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Reads a file's contents to a string list
 | 
			
		||||
     *
 | 
			
		||||
     * <p>The file must contain the number of lines to read in the first line.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @param fileName <p>The file to read.</p>
 | 
			
		||||
     * @return <p>A string list where each element is one line of the file.</p>
 | 
			
		||||
     * @throws IOException <p>If the file cannot be read.</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static String[] readFileLines(String fileName) throws IOException {
 | 
			
		||||
        BufferedReader reader = new BufferedReader(new InputStreamReader(getResourceAsStream(fileName)));
 | 
			
		||||
        int numberOfLines = Integer.parseInt(reader.readLine());
 | 
			
		||||
        String[] lines = new String[numberOfLines];
 | 
			
		||||
        for (int i = 0; i < lines.length; i++) {
 | 
			
		||||
            lines[i] = reader.readLine();
 | 
			
		||||
        }
 | 
			
		||||
        return lines;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a resource as an InputStream
 | 
			
		||||
     *
 | 
			
		||||
     * @param resourceName <p>The name of the resource you want to read.</p>
 | 
			
		||||
     * @return <p>An input stream which can be used to access the resource.</p>
 | 
			
		||||
     */
 | 
			
		||||
    private static InputStream getResourceAsStream(String resourceName) {
 | 
			
		||||
        ClassLoader classloader = Thread.currentThread().getContextClassLoader();
 | 
			
		||||
        return classloader.getResourceAsStream(resourceName);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Adds parentheses with an integer if the output file already exists
 | 
			
		||||
     *
 | 
			
		||||
@@ -105,7 +78,8 @@ public final class FileUtil {
 | 
			
		||||
     * @param extension  <p>The extension of the target file.</p>
 | 
			
		||||
     * @return <p>A filename guaranteed not to collide with other files.</p>
 | 
			
		||||
     */
 | 
			
		||||
    private static String getNonCollidingFilename(String targetPath, String extension) {
 | 
			
		||||
    @NotNull
 | 
			
		||||
    private static String getNonCollidingFilename(@NotNull String targetPath, @NotNull String extension) {
 | 
			
		||||
        File newFile = new File(targetPath);
 | 
			
		||||
        String fileName = stripExtension(targetPath).replaceAll("\\([0-9]+\\)$", "");
 | 
			
		||||
        int i = 1;
 | 
			
		||||
@@ -121,7 +95,8 @@ public final class FileUtil {
 | 
			
		||||
     * @param file <p>The filename to check</p>
 | 
			
		||||
     * @return <p>The file's extension</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static String getExtension(String file) {
 | 
			
		||||
    @NotNull
 | 
			
		||||
    public static String getExtension(@NotNull String file) {
 | 
			
		||||
        if (file.contains(".")) {
 | 
			
		||||
            return file.substring(file.lastIndexOf('.') + 1);
 | 
			
		||||
        } else {
 | 
			
		||||
@@ -135,7 +110,8 @@ public final class FileUtil {
 | 
			
		||||
     * @param file <p>A filename.</p>
 | 
			
		||||
     * @return <p>A filename without its extension.</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static String stripExtension(String file) {
 | 
			
		||||
    @NotNull
 | 
			
		||||
    public static String stripExtension(@NotNull String file) {
 | 
			
		||||
        return file.substring(0, file.lastIndexOf('.'));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,7 @@
 | 
			
		||||
package net.knarcraft.ffmpegconverter.utility;
 | 
			
		||||
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
 | 
			
		||||
import java.lang.reflect.Array;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
@@ -22,7 +24,8 @@ public final class ListUtil {
 | 
			
		||||
     * @param <T>   <p>The type of the two lists.</p>
 | 
			
		||||
     * @return <p>A new array containing all elements from the two arrays.</p>
 | 
			
		||||
     */
 | 
			
		||||
    static <T> T[] concatenate(T[] listA, T[] listB) {
 | 
			
		||||
    @NotNull
 | 
			
		||||
    public static <T> T[] concatenate(@NotNull T[] listA, @NotNull T[] listB) {
 | 
			
		||||
        int listALength = listA.length;
 | 
			
		||||
        int listBLength = listB.length;
 | 
			
		||||
        @SuppressWarnings("unchecked")
 | 
			
		||||
@@ -40,7 +43,7 @@ public final class ListUtil {
 | 
			
		||||
     * @param <T>       <p>The type of the list.</p>
 | 
			
		||||
     * @return <p>A new list containing all matching elements.</p>
 | 
			
		||||
     */
 | 
			
		||||
    static <T> List<T> getMatching(List<T> list, Predicate<T> predicate) {
 | 
			
		||||
    public static <T> List<T> getMatching(List<T> list, Predicate<T> predicate) {
 | 
			
		||||
        List<T> matching = new ArrayList<>(list);
 | 
			
		||||
        matching.removeIf(predicate.negate());
 | 
			
		||||
        return matching;
 | 
			
		||||
@@ -54,7 +57,7 @@ public final class ListUtil {
 | 
			
		||||
     * @param <T>       Anything which can be stored in a list
 | 
			
		||||
     * @return True if at least one element fulfills the predicate
 | 
			
		||||
     */
 | 
			
		||||
    static <T> boolean listContains(T[] list, Predicate<T> predicate) {
 | 
			
		||||
    public static <T> boolean listContains(@NotNull List<T> list, @NotNull Predicate<T> predicate) {
 | 
			
		||||
        for (T item : list) {
 | 
			
		||||
            if (predicate.test(item)) {
 | 
			
		||||
                return true;
 | 
			
		||||
@@ -69,7 +72,8 @@ public final class ListUtil {
 | 
			
		||||
     * @param string <p>A string which may include commas.</p>
 | 
			
		||||
     * @return <p>A string list.</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static String[] getListFromCommaSeparatedString(String string) {
 | 
			
		||||
    @NotNull
 | 
			
		||||
    public static String[] getListFromCommaSeparatedString(@NotNull String string) {
 | 
			
		||||
        String[] result;
 | 
			
		||||
        if (string.contains(",")) {
 | 
			
		||||
            result = string.split(",");
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,7 @@
 | 
			
		||||
package net.knarcraft.ffmpegconverter.utility;
 | 
			
		||||
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
 | 
			
		||||
import java.io.BufferedWriter;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.io.OutputStreamWriter;
 | 
			
		||||
@@ -30,7 +32,7 @@ public final class OutputUtil {
 | 
			
		||||
     *
 | 
			
		||||
     * @param input <p>The text to print.</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static void println(String input) {
 | 
			
		||||
    public static void println(@NotNull String input) {
 | 
			
		||||
        if (!input.isEmpty()) {
 | 
			
		||||
            try {
 | 
			
		||||
                writer.write(input);
 | 
			
		||||
@@ -46,7 +48,7 @@ public final class OutputUtil {
 | 
			
		||||
     *
 | 
			
		||||
     * @param input <p>The string to print.</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static void print(String input) {
 | 
			
		||||
    public static void print(@NotNull String input) {
 | 
			
		||||
        try {
 | 
			
		||||
            writer.write(input);
 | 
			
		||||
            writer.flush();
 | 
			
		||||
@@ -82,7 +84,7 @@ public final class OutputUtil {
 | 
			
		||||
     *
 | 
			
		||||
     * @param message <p>The debug message to show.</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static void printDebug(String message) {
 | 
			
		||||
    public static void printDebug(@NotNull String message) {
 | 
			
		||||
        if (debug) {
 | 
			
		||||
            println(message);
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
package net.knarcraft.ffmpegconverter.utility;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.ffmpegconverter.parser.ConverterArgument;
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
@@ -23,7 +24,8 @@ public final class Parser {
 | 
			
		||||
     * @param validArguments <p>All arguments which are considered valid.</p>
 | 
			
		||||
     * @return <p>A map with all parsed arguments.</p>
 | 
			
		||||
     */
 | 
			
		||||
    static Map<String, String> parse(String input, List<ConverterArgument> validArguments) {
 | 
			
		||||
    @NotNull
 | 
			
		||||
    static Map<String, String> parse(@NotNull String input, @NotNull List<ConverterArgument> validArguments) {
 | 
			
		||||
        return parse(tokenize(input), validArguments);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -34,7 +36,8 @@ public final class Parser {
 | 
			
		||||
     * @param validArguments <p>A list of arguments which are considered valid.</p>
 | 
			
		||||
     * @return <p>A map with all parsed arguments.</p>
 | 
			
		||||
     */
 | 
			
		||||
    private static Map<String, String> parse(List<String> tokens, List<ConverterArgument> validArguments) {
 | 
			
		||||
    @NotNull
 | 
			
		||||
    private static Map<String, String> parse(@NotNull List<String> tokens, @NotNull List<ConverterArgument> validArguments) {
 | 
			
		||||
        Map<String, String> parsedArguments = new HashMap<>();
 | 
			
		||||
 | 
			
		||||
        while (!tokens.isEmpty()) {
 | 
			
		||||
@@ -50,7 +53,8 @@ public final class Parser {
 | 
			
		||||
     * @param converterArguments <p>A list of all the valid arguments in existence.</p>
 | 
			
		||||
     * @param parsedArguments    <p>The map to store the parsed argument to.</p>
 | 
			
		||||
     */
 | 
			
		||||
    private static void parseArgument(List<String> tokens, List<ConverterArgument> converterArguments, Map<String, String> parsedArguments) {
 | 
			
		||||
    private static void parseArgument(@NotNull List<String> tokens, @NotNull List<ConverterArgument> converterArguments,
 | 
			
		||||
                                      @NotNull Map<String, String> parsedArguments) {
 | 
			
		||||
        String currentToken = tokens.remove(0);
 | 
			
		||||
        List<ConverterArgument> foundArguments;
 | 
			
		||||
 | 
			
		||||
@@ -79,7 +83,8 @@ public final class Parser {
 | 
			
		||||
     * @param foundArgument   <p>The found argument to store.</p>
 | 
			
		||||
     * @param parsedArguments <p>The map to store parsed arguments to.</p>
 | 
			
		||||
     */
 | 
			
		||||
    private static void storeArgumentValue(List<String> tokens, ConverterArgument foundArgument, Map<String, String> parsedArguments) {
 | 
			
		||||
    private static void storeArgumentValue(@NotNull List<String> tokens, @NotNull ConverterArgument foundArgument,
 | 
			
		||||
                                           @NotNull Map<String, String> parsedArguments) {
 | 
			
		||||
        String argumentValue;
 | 
			
		||||
        if (tokens.isEmpty()) {
 | 
			
		||||
            argumentValue = "";
 | 
			
		||||
@@ -114,7 +119,8 @@ public final class Parser {
 | 
			
		||||
     * @param input <p>A string.</p>
 | 
			
		||||
     * @return <p>A list of tokens.</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static List<String> tokenize(String input) {
 | 
			
		||||
    @NotNull
 | 
			
		||||
    public static List<String> tokenize(@NotNull String input) {
 | 
			
		||||
        List<String> tokens = new ArrayList<>();
 | 
			
		||||
        boolean startedQuote = false;
 | 
			
		||||
        StringBuilder currentToken = new StringBuilder();
 | 
			
		||||
@@ -157,8 +163,8 @@ public final class Parser {
 | 
			
		||||
     * @param index        <p>The index of the read character.</p>
 | 
			
		||||
     * @param tokens       <p>The list of processed tokens.</p>
 | 
			
		||||
     */
 | 
			
		||||
    private static void tokenizeNormalCharacter(StringBuilder currentToken, char character, int inputLength, int index,
 | 
			
		||||
                                                List<String> tokens) {
 | 
			
		||||
    private static void tokenizeNormalCharacter(@NotNull StringBuilder currentToken, char character, int inputLength,
 | 
			
		||||
                                                int index, @NotNull List<String> tokens) {
 | 
			
		||||
        currentToken.append(character);
 | 
			
		||||
        if (index == inputLength - 1) {
 | 
			
		||||
            tokens.add(currentToken.toString());
 | 
			
		||||
@@ -173,7 +179,8 @@ public final class Parser {
 | 
			
		||||
     * @param tokens       <p>The list of processed tokens.</p>
 | 
			
		||||
     * @return <p>True if the token is finished.</p>
 | 
			
		||||
     */
 | 
			
		||||
    private static boolean tokenizeSpace(boolean startedQuote, StringBuilder currentToken, List<String> tokens) {
 | 
			
		||||
    private static boolean tokenizeSpace(boolean startedQuote, @NotNull StringBuilder currentToken,
 | 
			
		||||
                                         @NotNull List<String> tokens) {
 | 
			
		||||
        if (!startedQuote) {
 | 
			
		||||
            //If not inside "", a space marks the end of a parameter
 | 
			
		||||
            if (isNotEmpty(currentToken)) {
 | 
			
		||||
@@ -192,7 +199,7 @@ public final class Parser {
 | 
			
		||||
     * @param builder <p>The string builder to check.</p>
 | 
			
		||||
     * @return <p>True if the string builder is non empty.</p>
 | 
			
		||||
     */
 | 
			
		||||
    private static boolean isNotEmpty(StringBuilder builder) {
 | 
			
		||||
    private static boolean isNotEmpty(@NotNull StringBuilder builder) {
 | 
			
		||||
        return !builder.toString().trim().isEmpty();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,3 @@
 | 
			
		||||
39
 | 
			
		||||
3gp
 | 
			
		||||
aa
 | 
			
		||||
aac
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1
									
								
								src/main/resources/conf/config.properties
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/main/resources/conf/config.properties
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
debug=false
 | 
			
		||||
@@ -1,4 +1,3 @@
 | 
			
		||||
5
 | 
			
		||||
idx
 | 
			
		||||
sub
 | 
			
		||||
srt
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,3 @@
 | 
			
		||||
31
 | 
			
		||||
avi
 | 
			
		||||
mpg
 | 
			
		||||
mpeg
 | 
			
		||||
 
 | 
			
		||||
@@ -13,7 +13,7 @@ import static org.junit.Assert.assertFalse;
 | 
			
		||||
 | 
			
		||||
public class ListUtilTest {
 | 
			
		||||
    private static List<Integer> matchesList;
 | 
			
		||||
    private static Integer[] containsList;
 | 
			
		||||
    private static List<Integer> containsList;
 | 
			
		||||
 | 
			
		||||
    @BeforeClass
 | 
			
		||||
    public static void setUp() {
 | 
			
		||||
@@ -28,7 +28,7 @@ public class ListUtilTest {
 | 
			
		||||
        matchesList.add(19);
 | 
			
		||||
        matchesList.add(21);
 | 
			
		||||
        matchesList.add(23);
 | 
			
		||||
        containsList = new Integer[]{1, 3, 5, 7, 234, 23, 45};
 | 
			
		||||
        containsList = List.of(1, 3, 5, 7, 234, 23, 45);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user