diff --git a/src/main/java/net/knarcraft/ffmpegconverter/FFMpegConvert.java b/src/main/java/net/knarcraft/ffmpegconverter/FFMpegConvert.java
index caf4c08..ac27f46 100644
--- a/src/main/java/net/knarcraft/ffmpegconverter/FFMpegConvert.java
+++ b/src/main/java/net/knarcraft/ffmpegconverter/FFMpegConvert.java
@@ -1,7 +1,6 @@
package net.knarcraft.ffmpegconverter;
-import net.knarcraft.ffmpegconverter.config.ConfigHandler;
-import net.knarcraft.ffmpegconverter.config.ConfigKey;
+import net.knarcraft.ffmpegconverter.config.Configuration;
import net.knarcraft.ffmpegconverter.converter.AnimeConverter;
import net.knarcraft.ffmpegconverter.converter.AudioConverter;
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.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;
@@ -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 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;
- private static boolean useHardwareAcceleration = false;
+ private static final Configuration configuration = new Configuration();
public static void main(@NotNull String[] arguments) throws IOException {
- Configuration configuration = configHandler.load();
- 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());
- }
+ OutputUtil.setDebug(configuration.isDebugEnabled());
converter = loadConverter();
@@ -85,27 +73,10 @@ public class FFMpegConvert {
* @return
The configuration handler
*/
@NotNull
- public static ConfigHandler getConfigHandler() {
- return configHandler;
+ public static Configuration getConfiguration() {
+ return configuration;
}
- /**
- * Gets whether debug mode is enabled
- *
- * @return True if debug mode is enabled
- */
- public static boolean isDebugEnabled() {
- return debug;
- }
-
- /**
- * Gets whether hardware accelerated encoding is enabled
- *
- * @return True if hardware accelerated encoding is enabled
- */
- public static boolean useHardwareAcceleration() {
- return useHardwareAcceleration;
- }
/**
* Asks the user which converter they want, and assigns a converter instance to the converter variable
@@ -230,51 +201,37 @@ public class FFMpegConvert {
*/
@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] " +
- "[Forced subtitle index 0-n] [Force video encoding true/false] [Force audio encoding true/false] " +
- "[Subtitle name filter]\nYour input: ");
- List input = readInput(8);
- String[] audioLanguage = new String[]{"jpn", "nor", "eng", "0"};
- String[] subtitleLanguage = new String[]{"nob", "nor", "eng", "jpn", "0"};
- MinimalSubtitlePreference subtitlePreference = MinimalSubtitlePreference.AVOID;
+ OutputUtil.println("[Forced audio index 0-n] [Forced subtitle index 0-n] [Force video encoding true/false] " +
+ "[Force audio encoding true/false] [Subtitle name filter]\nYour input: ");
+ List input = readInput(5);
int forcedAudioIndex = 0;
int forcedSubtitleIndex = 0;
String subtitleNameFilter = "";
boolean forceVideoEncoding = false;
boolean forceAudioEncoding = false;
- if (!input.isEmpty()) {
- audioLanguage = ListUtil.getListFromCommaSeparatedString(input.get(0));
- }
- if (input.size() > 1) {
- subtitleLanguage = ListUtil.getListFromCommaSeparatedString(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.isEmpty()) {
+ forcedAudioIndex = Integer.parseInt(input.get(0));
}
- if (input.size() > 4) {
- forcedSubtitleIndex = Integer.parseInt(input.get(4));
+ if (input.size() > 1) {
+ forcedSubtitleIndex = Integer.parseInt(input.get(1));
}
} catch (NumberFormatException exception) {
OutputUtil.println("Forced audio or subtitle index is not a number");
return null;
}
- if (input.size() > 5) {
- forceVideoEncoding = Boolean.parseBoolean(input.get(5));
+ if (input.size() > 2) {
+ forceVideoEncoding = Boolean.parseBoolean(input.get(2));
}
- if (input.size() > 6) {
- forceAudioEncoding = Boolean.parseBoolean(input.get(6));
+ if (input.size() > 3) {
+ forceAudioEncoding = Boolean.parseBoolean(input.get(3));
}
- if (input.size() > 7) {
- subtitleNameFilter = input.get(7);
+ if (input.size() > 4) {
+ subtitleNameFilter = input.get(4);
}
- return new AnimeConverter(FFPROBE_PATH, FFMPEG_PATH, audioLanguage, subtitleLanguage, subtitlePreference,
- forcedAudioIndex, forcedSubtitleIndex, subtitleNameFilter, forceVideoEncoding, forceAudioEncoding);
+ return new AnimeConverter(FFPROBE_PATH, FFMPEG_PATH, forcedAudioIndex, forcedSubtitleIndex, subtitleNameFilter,
+ forceVideoEncoding, forceAudioEncoding);
}
/**
@@ -284,12 +241,9 @@ public class FFMpegConvert {
*/
@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] " +
+ OutputUtil.println("[Convert to stereo if necessary true/false] [Prevent signs&songs subtitles true/false] [Forced audio index 0-n] " +
"[Forced subtitle index 0-n] [Subtitle name filter]\nYour input: ");
- List input = readInput(7);
- String[] audioLanguage = new String[]{"jpn", "0"};
- String[] subtitleLanguage = new String[]{"eng", "0"};
+ List input = readInput(5);
boolean toStereo = true;
MinimalSubtitlePreference subtitlePreference = MinimalSubtitlePreference.AVOID;
int forcedAudioIndex = 0;
@@ -297,32 +251,26 @@ public class FFMpegConvert {
String subtitleNameFilter = "";
if (!input.isEmpty()) {
- audioLanguage = ListUtil.getListFromCommaSeparatedString(input.get(0));
+ toStereo = Boolean.parseBoolean(input.get(0));
}
if (input.size() > 1) {
- subtitleLanguage = ListUtil.getListFromCommaSeparatedString(input.get(1));
- }
- if (input.size() > 2) {
- toStereo = Boolean.parseBoolean(input.get(2));
- }
- if (input.size() > 3) {
- subtitlePreference = MinimalSubtitlePreference.valueOf(input.get(3).toUpperCase());
+ subtitlePreference = MinimalSubtitlePreference.valueOf(input.get(1).toUpperCase());
}
try {
- if (input.size() > 4) {
- forcedAudioIndex = Integer.parseInt(input.get(4));
+ if (input.size() > 2) {
+ forcedAudioIndex = Integer.parseInt(input.get(2));
}
- if (input.size() > 5) {
- forcedSubtitleIndex = Integer.parseInt(input.get(5));
+ if (input.size() > 3) {
+ forcedSubtitleIndex = Integer.parseInt(input.get(3));
}
} catch (NumberFormatException exception) {
OutputUtil.println("Forced audio or subtitle index is not a number");
return null;
}
- if (input.size() > 6) {
- subtitleNameFilter = input.get(6);
+ if (input.size() > 4) {
+ 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);
}
diff --git a/src/main/java/net/knarcraft/ffmpegconverter/config/ConfigHandler.java b/src/main/java/net/knarcraft/ffmpegconverter/config/ConfigHandler.java
index 0f23de8..3ea271d 100644
--- a/src/main/java/net/knarcraft/ffmpegconverter/config/ConfigHandler.java
+++ b/src/main/java/net/knarcraft/ffmpegconverter/config/ConfigHandler.java
@@ -8,10 +8,12 @@ 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 org.jetbrains.annotations.Nullable;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
+import java.util.HashMap;
import java.util.Map;
/**
@@ -23,6 +25,18 @@ public class ConfigHandler {
private final Configurations configurations = new Configurations();
private final File settingsFile = new File(configFolder, "config.properties");
private FileBasedConfigurationBuilder builder = configurations.propertiesBuilder(settingsFile);
+ private final Map, Object> optionValues = new HashMap<>();
+
+ /**
+ * Gets the current value of a configuration option
+ *
+ * @param key The configuration key to get the value of
+ * @return The current value
+ */
+ @Nullable
+ public Object getValue(@NotNull ConfigKey> key) {
+ return optionValues.get(key);
+ }
/**
* Gets a writable configuration used for changing settings
@@ -64,11 +78,9 @@ public class ConfigHandler {
/**
* Loads the saved configuration file
- *
- * @return The loaded configuration
*/
- @NotNull
- public Configuration load() throws IOException {
+ public void load() throws IOException {
+ optionValues.clear();
Configuration configuration;
if (!settingsFile.exists()) {
configuration = new PropertiesConfiguration();
@@ -86,7 +98,14 @@ public class ConfigHandler {
}
// Reload contents in the builder
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());
+ }
+ }
}
}
diff --git a/src/main/java/net/knarcraft/ffmpegconverter/config/ConfigKey.java b/src/main/java/net/knarcraft/ffmpegconverter/config/ConfigKey.java
index 544a972..18ee56b 100644
--- a/src/main/java/net/knarcraft/ffmpegconverter/config/ConfigKey.java
+++ b/src/main/java/net/knarcraft/ffmpegconverter/config/ConfigKey.java
@@ -2,31 +2,106 @@ package net.knarcraft.ffmpegconverter.config;
import org.jetbrains.annotations.NotNull;
+import java.util.HashSet;
+import java.util.Set;
+
/**
* A representation of all configuration keys
*/
-public enum ConfigKey {
+public class ConfigKey {
+
+ private static final Set> allKeys = new HashSet<>();
/**
* The configuration key for the list of hardware-accelerated encoders available on the system
*/
- HARDWARE_ACCELERATED_ENCODERS("encoders-hardware-accelerated"),
+ public static final ConfigKey HARDWARE_ACCELERATED_ENCODERS = new ConfigKey<>("encoders-hardware-accelerated", String.class, "qsv,cuda,dxva2,d3d11va,opencl,vulkan");
/**
* The configuration key for toggling debug mode
*/
- DEBUG("debug"),
+ public static final ConfigKey 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 USE_HARDWARE_ENCODING = createKey("hardware-acceleration-encode", Boolean.class, false);
+
+ /**
+ * The configuration key for toggling hardware decoding
+ */
+ public static final ConfigKey USE_HARDWARE_DECODING = createKey("hardware-acceleration-decode", Boolean.class, true);
+
+ /**
+ * The configuration key for toggling forced flac encoding
+ */
+ public static final ConfigKey ENCODE_FLAC_ALWAYS = createKey("encode-flac-always", Boolean.class, false);
+
+ /**
+ * The configuration key for anime audio languages
+ */
+ public static final ConfigKey AUDIO_LANGUAGES_ANIME = createKey("audio-languages-anime", String.class, "jpn,eng,*");
+
+ /**
+ * The configuration key for anime subtitle languages
+ */
+ public static final ConfigKey SUBTITLE_LANGUAGES_ANIME = createKey("subtitle-languages-anime", String.class, "eng,*");
+
+ /**
+ * The configuration key for the minimal subtitle preference
+ */
+ public static final ConfigKey MINIMAL_SUBTITLE_PREFERENCE = createKey("minimal-subtitle-preference", String.class, "AVOID");
private final String configKey;
+ private final T defaultValue;
+ private final Class type;
- ConfigKey(@NotNull String configKey) {
+ /**
+ * Instantiates a new config key
+ *
+ * @param configKey The storage key in the configuration file
+ * @param type The type of this option's value
+ * @param defaultValue The default value of this option
+ */
+ private ConfigKey(@NotNull String configKey, @NotNull Class type, @NotNull T defaultValue) {
this.configKey = configKey;
+ this.type = type;
+ this.defaultValue = defaultValue;
+ }
+
+ /**
+ * Creates a new config key
+ *
+ * @param configKey The storage key in the configuration file
+ * @param type The type of this option's value
+ * @param defaultValue The default value of this option
+ * @param The type of key to create
+ * @return The new config key
+ */
+ private static ConfigKey createKey(@NotNull String configKey, @NotNull Class type, @NotNull F defaultValue) {
+ ConfigKey key = new ConfigKey<>(configKey, type, defaultValue);
+ allKeys.add(key);
+ return key;
+ }
+
+ /**
+ * Gets the type of this option's value
+ *
+ * @return The type of the value
+ */
+ @NotNull
+ public Class getType() {
+ return this.type;
+ }
+
+ /**
+ * Gets the default value for the option represented by this key
+ *
+ * @return The default value
+ */
+ @NotNull
+ public T getDefaultValue() {
+ return this.defaultValue;
}
@Override
@@ -34,4 +109,14 @@ public enum ConfigKey {
return this.configKey;
}
+ /**
+ * Gets all configuration keys
+ *
+ * @return All configuration keys
+ */
+ @NotNull
+ public static ConfigKey>[] values() {
+ return allKeys.toArray(new ConfigKey[0]);
+ }
+
}
diff --git a/src/main/java/net/knarcraft/ffmpegconverter/config/Configuration.java b/src/main/java/net/knarcraft/ffmpegconverter/config/Configuration.java
new file mode 100644
index 0000000..422aaa0
--- /dev/null
+++ b/src/main/java/net/knarcraft/ffmpegconverter/config/Configuration.java
@@ -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 hardwareEncoders;
+ private boolean alwaysEncodeFlac;
+ private List animeAudioLanguages;
+ private List 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 The underlying config handler
+ */
+ @NotNull
+ public ConfigHandler getConfigHandler() {
+ return this.configHandler;
+ }
+
+ /**
+ * Gets whether debug mode is enabled
+ *
+ * @return True if debug mode is enabled
+ */
+ public boolean isDebugEnabled() {
+ return this.debug;
+ }
+
+ /**
+ * Gets whether hardware accelerated encoding is enabled
+ *
+ * @return True if hardware accelerated encoding is enabled
+ */
+ public boolean useHardwareEncoding() {
+ return this.useHardwareEncoding;
+ }
+
+ /**
+ * Gets whether hardware accelerated decoding is enabled
+ *
+ * @return True if hardware accelerated decoding is enabled
+ */
+ public boolean useHardwareDecoding() {
+ return this.useHardwareDecoding;
+ }
+
+ /**
+ * Gets whether FLAC audio tracks should always be re-encoded
+ *
+ * @return Whether FLAC tracks should always be re-encoded
+ */
+ public boolean alwaysEncodeFlac() {
+ return this.alwaysEncodeFlac;
+ }
+
+ /**
+ * Gets all hardware encoders defined in the configuration
+ *
+ * @return The specified hardware encoders
+ */
+ @NotNull
+ public List hardwareEncoders() {
+ return this.hardwareEncoders;
+ }
+
+ /**
+ * Gets the audio language priorities for usage when converting anime
+ *
+ * @return The anime audio language priorities
+ */
+ @NotNull
+ public List getAnimeAudioLanguages() {
+ return this.animeAudioLanguages;
+ }
+
+ /**
+ * Gets the subtitle language priorities for usage when converting anime
+ *
+ * @return The anime subtitle language priorities
+ */
+ @NotNull
+ public List getAnimeSubtitleLanguages() {
+ return this.animeSubtitleLanguages;
+ }
+
+ /**
+ * Gets the preference for minimal subtitles
+ *
+ * @return The minimal subtitle preference
+ */
+ @NotNull
+ public MinimalSubtitlePreference getMinimalSubtitlePreference() {
+ return this.minimalSubtitlePreference;
+ }
+
+}
diff --git a/src/main/java/net/knarcraft/ffmpegconverter/converter/AbstractConverter.java b/src/main/java/net/knarcraft/ffmpegconverter/converter/AbstractConverter.java
index b82118b..5e117d1 100644
--- a/src/main/java/net/knarcraft/ffmpegconverter/converter/AbstractConverter.java
+++ b/src/main/java/net/knarcraft/ffmpegconverter/converter/AbstractConverter.java
@@ -4,6 +4,7 @@ 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.streams.StreamObject;
import net.knarcraft.ffmpegconverter.utility.FFMpegHelper;
import net.knarcraft.ffmpegconverter.utility.FileHelper;
import net.knarcraft.ffmpegconverter.utility.FileUtil;
@@ -21,7 +22,7 @@ import java.util.List;
*/
public abstract class AbstractConverter implements Converter {
- final boolean debug = FFMpegConvert.isDebugEnabled();
+ final boolean debug = FFMpegConvert.getConfiguration().isDebugEnabled();
private final String newExtension;
protected String ffprobePath;
protected String ffmpegPath;
@@ -136,4 +137,18 @@ public abstract class AbstractConverter implements Converter {
return encoderHandler.availableHardwareEncodings();
}
+ /**
+ * Sets the output indexes for the given streams
+ *
+ * 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.
+ *
+ * @param streams The streams to set the output indexes for
+ */
+ protected void setOutputIndexes(@NotNull List streams) {
+ for (int i = 0; i < streams.size(); i++) {
+ streams.get(i).setOutputIndex(i);
+ }
+ }
+
}
diff --git a/src/main/java/net/knarcraft/ffmpegconverter/converter/AnimeConverter.java b/src/main/java/net/knarcraft/ffmpegconverter/converter/AnimeConverter.java
index 8d99581..66d1ad1 100644
--- a/src/main/java/net/knarcraft/ffmpegconverter/converter/AnimeConverter.java
+++ b/src/main/java/net/knarcraft/ffmpegconverter/converter/AnimeConverter.java
@@ -1,6 +1,7 @@
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.StreamProbeResult;
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.SetOutputFileModule;
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.sorter.AudioLanguageSorter;
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.VideoStream;
import net.knarcraft.ffmpegconverter.utility.FFMpegHelper;
+import net.knarcraft.ffmpegconverter.utility.OutputUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
/**
@@ -40,8 +44,8 @@ import java.util.List;
*/
public class AnimeConverter extends AbstractConverter {
- private final String[] audioLanguages;
- private final String[] subtitleLanguages;
+ private final List audioLanguages;
+ private final List subtitleLanguages;
private final MinimalSubtitlePreference subtitlePreference;
private final int forcedAudioIndex;
private final int forcedSubtitleIndex;
@@ -54,25 +58,21 @@ public class AnimeConverter extends AbstractConverter {
*
* @param ffprobePath Path/command to ffprobe.
* @param ffmpegPath Path/command to ffmpeg.
- * @param audioLanguages List of wanted audio languages in descending order.
- * @param subtitleLanguages List of wanted subtitle languages in descending order.
- * @param subtitlePreference How minimal subtitles should be prioritized
* @param forcedAudioIndex A specific audio stream to force as default. 0-indexed from the first audio stream found
* @param forcedSubtitleIndex A specific subtitle stream to force as default. 0-indexed for the first subtitle stream found
* @param forceVideoEncoding Whether to enforce encoding on the video, even if already hevc
* @param forceAudioEncoding Whether to convert audio to web-playable, even though there should be no need
*/
- public AnimeConverter(@NotNull String ffprobePath, @NotNull String ffmpegPath, @NotNull String[] audioLanguages,
- @NotNull String[] subtitleLanguages,
- @NotNull MinimalSubtitlePreference subtitlePreference, int forcedAudioIndex,
+ public AnimeConverter(@NotNull String ffprobePath, @NotNull String ffmpegPath, int forcedAudioIndex,
int forcedSubtitleIndex, @NotNull String subtitleNameFilter, boolean forceVideoEncoding,
boolean forceAudioEncoding) {
super("mkv");
+ Configuration configuration = FFMpegConvert.getConfiguration();
this.ffprobePath = ffprobePath;
this.ffmpegPath = ffmpegPath;
- this.audioLanguages = audioLanguages;
- this.subtitleLanguages = subtitleLanguages;
- this.subtitlePreference = subtitlePreference;
+ this.audioLanguages = configuration.getAnimeAudioLanguages();
+ this.subtitleLanguages = configuration.getAnimeSubtitleLanguages();
+ this.subtitlePreference = configuration.getMinimalSubtitlePreference();
this.forcedAudioIndex = forcedAudioIndex;
this.forcedSubtitleIndex = forcedSubtitleIndex;
this.subtitleNameFilter = subtitleNameFilter;
@@ -85,6 +85,7 @@ public class AnimeConverter extends AbstractConverter {
public FFMpegCommand generateConversionCommand(@NotNull String executable,
@NotNull StreamProbeResult probeResult,
@NotNull String outFile) {
+ Configuration configuration = FFMpegConvert.getConfiguration();
FFMpegCommand command = FFMpegHelper.getFFMpegGeneralFileCommand(executable, probeResult.parsedFiles());
List modules = new ArrayList<>();
if (this.debug) {
@@ -92,16 +93,20 @@ public class AnimeConverter extends AbstractConverter {
}
modules.add(new FastStartModule());
- //Get the first video stream
- modules.add(new MapAllModule<>(probeResult.getVideoStreams()));
+ //Map all video streams
+ List videoStreams = probeResult.getVideoStreams();
+ modules.add(new MapAllModule<>(videoStreams));
+ setOutputIndexes(videoStreams);
//Get the first audio stream in accordance with chosen languages
StreamSorter audioSorter = new AudioLanguageSorter(this.audioLanguages)
.append(new ForcedFirstSorter<>(this.forcedAudioIndex))
.append(new SpecialAudioSorter(MinimalSubtitlePreference.REJECT));
List sortedAudio = audioSorter.chainSort(probeResult.getAudioStreams());
+ setOutputIndexes(sortedAudio);
modules.add(new MapAllModule<>(sortedAudio));
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
StreamSorter subtitleSorter = new SubtitleTitleSorter(
@@ -109,13 +114,24 @@ public class AnimeConverter extends AbstractConverter {
.append(new SubtitleLanguageSorter(this.subtitleLanguages))
.append(new MinimalSubtitleSorter(this.subtitlePreference))
.append(new ForcedFirstSorter<>(this.forcedSubtitleIndex));
- List sorted = subtitleSorter.chainSort(probeResult.getSubtitleStreams());
- modules.add(new MapAllModule<>(sorted));
- modules.add(new SetDefaultStreamModule<>(sorted, 0));
+ List sortedSubtitles = subtitleSorter.chainSort(probeResult.getSubtitleStreams());
+ setOutputIndexes(sortedSubtitles);
+ 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()));
- modules.add(new HardwareDecodeModule());
- if (!this.forceAudioEncoding) {
- modules.add(new CopyAudioModule());
+ if (configuration.useHardwareDecoding()) {
+ modules.add(new HardwareDecodeModule());
+ }
+
+ 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());
@@ -129,10 +145,10 @@ public class AnimeConverter extends AbstractConverter {
if (encodingNecessary || this.forceVideoEncoding) {
List availableHWAcceleration = getAvailableHardwareEncodingMethods();
- if (FFMpegConvert.useHardwareAcceleration() && availableHWAcceleration.contains("qsv")) {
+ if (configuration.useHardwareEncoding() && availableHWAcceleration.contains("qsv")) {
modules.add(new SetVideoCodecModule("hevc_qsv"));
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));
} else {
modules.add(new SetVideoCodecModule("hevc"));
diff --git a/src/main/java/net/knarcraft/ffmpegconverter/converter/MkvH264Converter.java b/src/main/java/net/knarcraft/ffmpegconverter/converter/MkvH264Converter.java
index 82afdf4..4a51198 100644
--- a/src/main/java/net/knarcraft/ffmpegconverter/converter/MkvH264Converter.java
+++ b/src/main/java/net/knarcraft/ffmpegconverter/converter/MkvH264Converter.java
@@ -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.FastStartModule;
import net.knarcraft.ffmpegconverter.converter.module.output.SetOutputFileModule;
+import net.knarcraft.ffmpegconverter.streams.AudioStream;
import net.knarcraft.ffmpegconverter.streams.StreamObject;
import net.knarcraft.ffmpegconverter.utility.FFMpegHelper;
import org.jetbrains.annotations.NotNull;
@@ -64,9 +65,11 @@ public class MkvH264Converter extends AbstractConverter {
}
// Map audio if present
- if (!probeResult.getAudioStreams().isEmpty()) {
- modules.add(new MapAllModule<>(probeResult.getAudioStreams()));
- modules.add(new CopyAudioModule());
+ List audioStreams = probeResult.getAudioStreams();
+ if (!audioStreams.isEmpty()) {
+ modules.add(new MapAllModule<>(audioStreams));
+ setOutputIndexes(audioStreams);
+ modules.add(new CopyAudioModule(audioStreams));
}
// Map subtitles if present
diff --git a/src/main/java/net/knarcraft/ffmpegconverter/converter/MkvH265ReducedConverter.java b/src/main/java/net/knarcraft/ffmpegconverter/converter/MkvH265ReducedConverter.java
index e6b0a42..33fba68 100644
--- a/src/main/java/net/knarcraft/ffmpegconverter/converter/MkvH265ReducedConverter.java
+++ b/src/main/java/net/knarcraft/ffmpegconverter/converter/MkvH265ReducedConverter.java
@@ -69,7 +69,8 @@ public class MkvH265ReducedConverter extends AbstractConverter {
List audioStreams = probeResult.getAudioStreams();
if (!audioStreams.isEmpty()) {
modules.add(new MapAllModule<>(audioStreams));
- modules.add(new CopyAudioModule());
+ setOutputIndexes(audioStreams);
+ modules.add(new CopyAudioModule(audioStreams));
}
// Map subtitles if present
diff --git a/src/main/java/net/knarcraft/ffmpegconverter/converter/SubtitleEmbed.java b/src/main/java/net/knarcraft/ffmpegconverter/converter/SubtitleEmbed.java
index c671214..a91ed0b 100644
--- a/src/main/java/net/knarcraft/ffmpegconverter/converter/SubtitleEmbed.java
+++ b/src/main/java/net/knarcraft/ffmpegconverter/converter/SubtitleEmbed.java
@@ -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.mapping.MapAllModule;
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.SetOutputFileModule;
+import net.knarcraft.ffmpegconverter.streams.AudioStream;
import net.knarcraft.ffmpegconverter.utility.FFMpegHelper;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -53,8 +55,10 @@ public class SubtitleEmbed extends AbstractConverter {
modules.add(new MapAllModule<>(probeResult.parsedStreams()));
modules.add(new HardwareDecodeModule());
- modules.add(new CopyAudioModule());
- modules.add(new CopyAudioModule());
+ List audioStreams = probeResult.getAudioStreams();
+ setOutputIndexes(audioStreams);
+ modules.add(new CopyAudioModule(audioStreams));
+ modules.add(new CopyVideoModule());
modules.add(new MovTextModule());
modules.add(new SetOutputFileModule(outFile));
diff --git a/src/main/java/net/knarcraft/ffmpegconverter/converter/WebAnimeConverter.java b/src/main/java/net/knarcraft/ffmpegconverter/converter/WebAnimeConverter.java
index 66cad0a..c3f0442 100644
--- a/src/main/java/net/knarcraft/ffmpegconverter/converter/WebAnimeConverter.java
+++ b/src/main/java/net/knarcraft/ffmpegconverter/converter/WebAnimeConverter.java
@@ -1,5 +1,7 @@
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.StreamProbeResult;
import net.knarcraft.ffmpegconverter.converter.module.ConverterModule;
@@ -33,8 +35,8 @@ import static net.knarcraft.ffmpegconverter.utility.FFMpegHelper.getNthSteam;
*/
public class WebAnimeConverter extends AbstractConverter {
- private final String[] audioLanguages;
- private final String[] subtitleLanguages;
+ private final List audioLanguages;
+ private final List subtitleLanguages;
private final boolean toStereo;
private final MinimalSubtitlePreference subtitlePreference;
private final int forcedAudioIndex;
@@ -46,22 +48,20 @@ public class WebAnimeConverter extends AbstractConverter {
*
* @param ffprobePath Path/command to ffprobe.
* @param ffmpegPath Path/command to ffmpeg.
- * @param audioLanguages List of wanted audio languages in descending order.
- * @param subtitleLanguages List of wanted subtitle languages in descending order.
* @param toStereo Convert video with several audio channels to stereo.
* @param subtitlePreference How minimal subtitles should be prioritized
* @param forcedAudioIndex A specific audio stream to force. 0-indexed from the first audio stream found
* @param forcedSubtitleIndex A specific subtitle stream to force. 0-indexed for the first subtitle stream found
*/
- public WebAnimeConverter(@NotNull String ffprobePath, @NotNull String ffmpegPath, @NotNull String[] audioLanguages,
- @NotNull String[] subtitleLanguages, boolean toStereo,
+ public WebAnimeConverter(@NotNull String ffprobePath, @NotNull String ffmpegPath, boolean toStereo,
@NotNull MinimalSubtitlePreference subtitlePreference, int forcedAudioIndex,
int forcedSubtitleIndex, @NotNull String subtitleNameFilter) {
super("mp4");
+ Configuration configuration = FFMpegConvert.getConfiguration();
this.ffprobePath = ffprobePath;
this.ffmpegPath = ffmpegPath;
- this.audioLanguages = audioLanguages;
- this.subtitleLanguages = subtitleLanguages;
+ this.audioLanguages = configuration.getAnimeAudioLanguages();
+ this.subtitleLanguages = configuration.getAnimeSubtitleLanguages();
this.toStereo = toStereo;
this.subtitlePreference = subtitlePreference;
this.forcedAudioIndex = forcedAudioIndex;
diff --git a/src/main/java/net/knarcraft/ffmpegconverter/converter/module/output/CopyAudioModule.java b/src/main/java/net/knarcraft/ffmpegconverter/converter/module/output/CopyAudioModule.java
index 45a77e4..3b3610e 100644
--- a/src/main/java/net/knarcraft/ffmpegconverter/converter/module/output/CopyAudioModule.java
+++ b/src/main/java/net/knarcraft/ffmpegconverter/converter/module/output/CopyAudioModule.java
@@ -2,16 +2,56 @@ 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.AudioStream;
+import net.knarcraft.ffmpegconverter.streams.StreamObject;
import org.jetbrains.annotations.NotNull;
+import java.util.List;
+
/**
* A module for making FFMpeg copy the audio codec
*/
public class CopyAudioModule implements ConverterModule {
+ private final List streams;
+
+ /**
+ * Instantiates a new copy audio module
+ *
+ * @param streams The streams to specify the copy flag for, or null to not use a per-stream selector
+ */
+ public CopyAudioModule(@NotNull List streams) {
+ this.streams = streams;
+ }
+
+ /**
+ * Instantiates a new copy audio module
+ *
+ * @param stream The stream to specify the copy flag for
+ */
+ public CopyAudioModule(@NotNull AudioStream stream) {
+ this.streams = List.of(stream);
+ }
+
+ /**
+ * Instantiates a new copy audio module
+ */
+ public CopyAudioModule() {
+ this.streams = null;
+ }
+
@Override
public void addArguments(@NotNull FFMpegCommand command) {
- command.addOutputFileOption("-c:a", "copy");
+ 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");
+ }
}
}
diff --git a/src/main/java/net/knarcraft/ffmpegconverter/converter/module/output/SetStreamLanguageModule.java b/src/main/java/net/knarcraft/ffmpegconverter/converter/module/output/SetStreamLanguageModule.java
new file mode 100644
index 0000000..c97a38e
--- /dev/null
+++ b/src/main/java/net/knarcraft/ffmpegconverter/converter/module/output/SetStreamLanguageModule.java
@@ -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 The type of stream to set language for
+ */
+public class SetStreamLanguageModule implements ConverterModule {
+
+ private final List streams;
+
+ /**
+ * Instantiates a new set stream language module
+ *
+ * @param streams The streams to set language for
+ */
+ public SetStreamLanguageModule(@NotNull List 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()));
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/net/knarcraft/ffmpegconverter/converter/sorter/AbstractSorter.java b/src/main/java/net/knarcraft/ffmpegconverter/converter/sorter/AbstractSorter.java
index 57ef3ad..7a06e3e 100644
--- a/src/main/java/net/knarcraft/ffmpegconverter/converter/sorter/AbstractSorter.java
+++ b/src/main/java/net/knarcraft/ffmpegconverter/converter/sorter/AbstractSorter.java
@@ -71,7 +71,7 @@ public abstract class AbstractSorter implements StreamSo
*/
@NotNull
protected List sortStreamsByLanguage(@NotNull List streams,
- @NotNull String[] languages) {
+ @NotNull List languages) {
List sorted = new ArrayList<>();
for (String language : languages) {
for (G stream : streams) {
diff --git a/src/main/java/net/knarcraft/ffmpegconverter/converter/sorter/AudioLanguageSorter.java b/src/main/java/net/knarcraft/ffmpegconverter/converter/sorter/AudioLanguageSorter.java
index c87cc2a..dc330d5 100644
--- a/src/main/java/net/knarcraft/ffmpegconverter/converter/sorter/AudioLanguageSorter.java
+++ b/src/main/java/net/knarcraft/ffmpegconverter/converter/sorter/AudioLanguageSorter.java
@@ -10,14 +10,14 @@ import java.util.List;
*/
public class AudioLanguageSorter extends AbstractSorter {
- private final String[] languageOrder;
+ private final List languageOrder;
/**
* Instantiates a new audio language sorter
*
* @param languageOrder The order of preference for audio languages
*/
- public AudioLanguageSorter(@NotNull String[] languageOrder) {
+ public AudioLanguageSorter(@NotNull List languageOrder) {
this.languageOrder = languageOrder;
}
diff --git a/src/main/java/net/knarcraft/ffmpegconverter/converter/sorter/SubtitleLanguageSorter.java b/src/main/java/net/knarcraft/ffmpegconverter/converter/sorter/SubtitleLanguageSorter.java
index f584c0d..91f62de 100644
--- a/src/main/java/net/knarcraft/ffmpegconverter/converter/sorter/SubtitleLanguageSorter.java
+++ b/src/main/java/net/knarcraft/ffmpegconverter/converter/sorter/SubtitleLanguageSorter.java
@@ -11,14 +11,14 @@ import java.util.List;
*/
public class SubtitleLanguageSorter extends AbstractSorter {
- private final String[] languageOrder;
+ private final List languageOrder;
/**
* Instantiates a new subtitle language sorter
*
* @param languageOrder The order of preference for subtitle languages
*/
- public SubtitleLanguageSorter(@NotNull String[] languageOrder) {
+ public SubtitleLanguageSorter(@NotNull List languageOrder) {
this.languageOrder = languageOrder;
}
diff --git a/src/main/java/net/knarcraft/ffmpegconverter/converter/sorter/SubtitleTitleSorter.java b/src/main/java/net/knarcraft/ffmpegconverter/converter/sorter/SubtitleTitleSorter.java
index 2161027..b3837bd 100644
--- a/src/main/java/net/knarcraft/ffmpegconverter/converter/sorter/SubtitleTitleSorter.java
+++ b/src/main/java/net/knarcraft/ffmpegconverter/converter/sorter/SubtitleTitleSorter.java
@@ -45,7 +45,7 @@ public class SubtitleTitleSorter extends AbstractSorter {
boolean isRegEx = isValidRegularExpression(filter) && hasSpecialRegexCharacters(filter);
- if (FFMpegConvert.isDebugEnabled()) {
+ if (FFMpegConvert.getConfiguration().isDebugEnabled()) {
System.out.println("Filtering subtitles by filter " + filter + ". RegEx is " + isRegEx);
}
diff --git a/src/main/java/net/knarcraft/ffmpegconverter/handler/AvailableHardwareEncoderHandler.java b/src/main/java/net/knarcraft/ffmpegconverter/handler/AvailableHardwareEncoderHandler.java
index 9b014b5..3aeadb4 100644
--- a/src/main/java/net/knarcraft/ffmpegconverter/handler/AvailableHardwareEncoderHandler.java
+++ b/src/main/java/net/knarcraft/ffmpegconverter/handler/AvailableHardwareEncoderHandler.java
@@ -4,7 +4,6 @@ import net.knarcraft.ffmpegconverter.FFMpegConvert;
import net.knarcraft.ffmpegconverter.config.ConfigHandler;
import net.knarcraft.ffmpegconverter.config.ConfigKey;
import net.knarcraft.ffmpegconverter.utility.OutputUtil;
-import org.apache.commons.configuration2.Configuration;
import org.apache.commons.configuration2.PropertiesConfiguration;
import org.jetbrains.annotations.NotNull;
@@ -17,7 +16,7 @@ import java.util.List;
*/
public record AvailableHardwareEncoderHandler(@NotNull List availableHardwareEncodings) {
- private static final ConfigHandler configHandler = FFMpegConvert.getConfigHandler();
+ private static final ConfigHandler configHandler = FFMpegConvert.getConfiguration().getConfigHandler();
/**
* Gets all hardware encodings
@@ -44,7 +43,7 @@ public record AvailableHardwareEncoderHandler(@NotNull List availableHar
*/
public void save() {
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();
OutputUtil.printDebug("Saved available hardware encoder handler");
}
@@ -56,14 +55,12 @@ public record AvailableHardwareEncoderHandler(@NotNull List availableHar
*/
@NotNull
public static AvailableHardwareEncoderHandler load() {
- Configuration configuration;
try {
- configuration = configHandler.load();
+ configHandler.load();
} catch (IOException e) {
throw new RuntimeException(e);
}
- List getEncodings = configuration.getList(String.class, ConfigKey.HARDWARE_ACCELERATED_ENCODERS.toString());
- return new AvailableHardwareEncoderHandler(getEncodings);
+ return new AvailableHardwareEncoderHandler(FFMpegConvert.getConfiguration().hardwareEncoders());
}
}
diff --git a/src/main/java/net/knarcraft/ffmpegconverter/streams/AbstractStream.java b/src/main/java/net/knarcraft/ffmpegconverter/streams/AbstractStream.java
index f6f62a9..52f542c 100644
--- a/src/main/java/net/knarcraft/ffmpegconverter/streams/AbstractStream.java
+++ b/src/main/java/net/knarcraft/ffmpegconverter/streams/AbstractStream.java
@@ -17,6 +17,7 @@ public abstract class AbstractStream implements StreamObject {
protected final String language;
protected final boolean isDefault;
protected final String title;
+ protected int outputIndex;
/**
* Instantiates a new abstract stream
@@ -28,11 +29,12 @@ public abstract class AbstractStream implements StreamObject {
protected AbstractStream(@NotNull Map streamInfo, int inputIndex, int relativeIndex) {
this.codecName = ValueParsingHelper.parseString(streamInfo.get(StreamTag.CODEC_NAME), "");
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.title = ValueParsingHelper.parseString(streamInfo.get(StreamTag.TAG_TITLE), "");
this.inputIndex = inputIndex;
this.relativeIndex = relativeIndex;
+ this.outputIndex = -1;
}
@Override
@@ -73,4 +75,40 @@ public abstract class AbstractStream implements StreamObject {
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
+ *
+ * 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.
+ *
+ * @param streamInfo All info about the stream
+ * @return The actual language
+ */
+ @NotNull
+ private String parseLanguage(@NotNull Map 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;
+ }
+
}
\ No newline at end of file
diff --git a/src/main/java/net/knarcraft/ffmpegconverter/streams/StreamObject.java b/src/main/java/net/knarcraft/ffmpegconverter/streams/StreamObject.java
index 95c1437..44fcb13 100644
--- a/src/main/java/net/knarcraft/ffmpegconverter/streams/StreamObject.java
+++ b/src/main/java/net/knarcraft/ffmpegconverter/streams/StreamObject.java
@@ -5,6 +5,7 @@ import org.jetbrains.annotations.NotNull;
/**
* An object describing a generic video file stream
*/
+@SuppressWarnings("unused")
public interface StreamObject {
/**
@@ -68,4 +69,21 @@ public interface StreamObject {
*/
char streamTypeCharacter();
+ /**
+ * Gets the index of this stream in the output file
+ *
+ * @return The index of this stream in the output file, or -1 if not set
+ */
+ int getOutputIndex();
+
+ /**
+ * Sets the index of this stream in the output file
+ *
+ * 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
+ *
+ * @param newIndex The new output index
+ */
+ void setOutputIndex(int newIndex);
+
}
diff --git a/src/main/java/net/knarcraft/ffmpegconverter/streams/SubtitleStream.java b/src/main/java/net/knarcraft/ffmpegconverter/streams/SubtitleStream.java
index 0dbe9da..81adee0 100644
--- a/src/main/java/net/knarcraft/ffmpegconverter/streams/SubtitleStream.java
+++ b/src/main/java/net/knarcraft/ffmpegconverter/streams/SubtitleStream.java
@@ -51,7 +51,7 @@ public class SubtitleStream extends AbstractStream implements StreamObject {
*/
private boolean checkIfIsFullSubtitle() {
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(".*forced.*") &&
!titleLowercase.matches(".*s&s.*") &&
@@ -68,4 +68,10 @@ public class SubtitleStream extends AbstractStream implements StreamObject {
return 's';
}
+ @Override
+ @NotNull
+ public String toString() {
+ return super.toString() + " | Is full: " + this.isFullSubtitle;
+ }
+
}
\ No newline at end of file
diff --git a/src/main/java/net/knarcraft/ffmpegconverter/utility/ConfigHelper.java b/src/main/java/net/knarcraft/ffmpegconverter/utility/ConfigHelper.java
new file mode 100644
index 0000000..829b978
--- /dev/null
+++ b/src/main/java/net/knarcraft/ffmpegconverter/utility/ConfigHelper.java
@@ -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 The raw string list value
+ * @return The value as a string list, or null if not compatible
+ */
+ public static @NotNull List 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 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
+ *
+ * This will throw an exception if used for a non-boolean value
+ *
+ * @param value The object value to get
+ * @return The value of the given object as a boolean
+ * @throws ClassCastException If the given value is not a boolean
+ */
+ 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();
+ }
+ }
+
+}
diff --git a/src/main/resources/conf/config.properties b/src/main/resources/conf/config.properties
index 513139f..e23f1ec 100644
--- a/src/main/resources/conf/config.properties
+++ b/src/main/resources/conf/config.properties
@@ -3,4 +3,16 @@
debug=false
# 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.
-hardware-acceleration=false
\ No newline at end of file
+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
\ No newline at end of file