Compare commits
10 Commits
master
...
advanced-a
Author | SHA1 | Date | |
---|---|---|---|
17f72e0892 | |||
8b0c1ea815 | |||
d349629574 | |||
a0b5b65054 | |||
1e3544f793 | |||
d6754b61cb | |||
8ffd4184d3 | |||
40a2f58712 | |||
ffbe4c5c31 | |||
d0e4a7b3cc |
@ -18,7 +18,7 @@ import java.util.List;
|
||||
*/
|
||||
public abstract class AbstractConverter implements Converter {
|
||||
final boolean debug = false;
|
||||
private final String newExtension;
|
||||
private final String outputExtension;
|
||||
String ffprobePath;
|
||||
String ffmpegPath;
|
||||
String[] audioFormats;
|
||||
@ -27,8 +27,8 @@ public abstract class AbstractConverter implements Converter {
|
||||
/**
|
||||
* Initializes variables used by the abstract converter
|
||||
*/
|
||||
AbstractConverter(String newExtension) {
|
||||
this.newExtension = newExtension;
|
||||
AbstractConverter(String outputExtension) {
|
||||
this.outputExtension = outputExtension;
|
||||
OutputUtil.setDebug(this.debug);
|
||||
try {
|
||||
audioFormats = FileUtil.readFileLines("audio_formats.txt");
|
||||
@ -127,7 +127,7 @@ public abstract class AbstractConverter implements Converter {
|
||||
throw new IllegalArgumentException("The file has no valid streams. Please make sure the file exists and" +
|
||||
" is not corrupt.");
|
||||
}
|
||||
String newPath = FileUtil.getNonCollidingPath(folder, file, newExtension);
|
||||
String newPath = FileUtil.getNonCollidingPath(folder, file, outputExtension);
|
||||
OutputUtil.println();
|
||||
OutputUtil.println("Preparing to start process...");
|
||||
OutputUtil.println("Converting " + file);
|
||||
@ -138,11 +138,10 @@ public abstract class AbstractConverter implements Converter {
|
||||
/**
|
||||
* Gets the first audio stream from a list of streams
|
||||
*
|
||||
* @param streams <p>A list of all streams.</p>
|
||||
* @param audioStreams <p>A list of all streams.</p>
|
||||
* @return <p>The first audio stream found or null if no audio streams were found.</p>
|
||||
*/
|
||||
AudioStream getFirstAudioSteam(List<StreamObject> streams) {
|
||||
List<AudioStream> audioStreams = filterStreamsByType(streams, AudioStream.class);
|
||||
AudioStream getFirstAudioStream(List<AudioStream> audioStreams) {
|
||||
AudioStream audioStream = null;
|
||||
if (audioStreams.size() > 0) {
|
||||
audioStream = audioStreams.get(0);
|
||||
@ -153,11 +152,10 @@ public abstract class AbstractConverter implements Converter {
|
||||
/**
|
||||
* Gets the first subtitle stream from a list of streams
|
||||
*
|
||||
* @param streams <p>A list of all streams.</p>
|
||||
* @param subtitleStreams <p>A list of all subtitle streams.</p>
|
||||
* @return <p>The first subtitle stream found or null if no subtitle streams were found.</p>
|
||||
*/
|
||||
SubtitleStream getFirstSubtitleStream(List<StreamObject> streams) {
|
||||
List<SubtitleStream> subtitleStreams = filterStreamsByType(streams, SubtitleStream.class);
|
||||
SubtitleStream getFirstSubtitleStream(List<SubtitleStream> subtitleStreams) {
|
||||
SubtitleStream subtitleStream = null;
|
||||
if (subtitleStreams.size() > 0) {
|
||||
subtitleStream = subtitleStreams.get(0);
|
||||
@ -168,11 +166,10 @@ public abstract class AbstractConverter implements Converter {
|
||||
/**
|
||||
* Gets the first video stream from a list of streams
|
||||
*
|
||||
* @param streams <p>A list of all streams.</p>
|
||||
* @param videoStreams <p>A list of all streams.</p>
|
||||
* @return <p>The first video stream found or null if no video streams were found.</p>
|
||||
*/
|
||||
VideoStream getFirstVideoStream(List<StreamObject> streams) {
|
||||
List<VideoStream> videoStreams = filterStreamsByType(streams, VideoStream.class);
|
||||
VideoStream getFirstVideoStream(List<VideoStream> videoStreams) {
|
||||
VideoStream videoStream = null;
|
||||
if (videoStreams.size() > 0) {
|
||||
videoStream = videoStreams.get(0);
|
||||
|
@ -0,0 +1,122 @@
|
||||
package net.knarcraft.ffmpegconverter.converter;
|
||||
|
||||
import net.knarcraft.ffmpegconverter.streams.AudioStream;
|
||||
import net.knarcraft.ffmpegconverter.streams.StreamObject;
|
||||
import net.knarcraft.ffmpegconverter.streams.SubtitleStream;
|
||||
import net.knarcraft.ffmpegconverter.streams.VideoStream;
|
||||
import net.knarcraft.ffmpegconverter.utility.FFMpegHelper;
|
||||
import net.knarcraft.ffmpegconverter.utility.ListUtil;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class AdvancedConverter extends AbstractConverter {
|
||||
|
||||
private boolean burnFirstSubtitle = true;
|
||||
private boolean burnFirstAudio = true;
|
||||
private String videoCodec = "h264";
|
||||
private String pixelFormat = "yuv420p";
|
||||
private int audioSamplingFrequency = 48000;
|
||||
private boolean moveHeaders = true;
|
||||
private boolean convertToStereo = true;
|
||||
private boolean preventPartialSubtitles = true;
|
||||
private String[] audioLanguages = new String[]{"jpn", "eng", "0"};
|
||||
private String[] subtitleLanguages = new String[]{"eng", "0"};
|
||||
private String outputExtension = "mp4";
|
||||
private boolean autoStreamSelection = false;
|
||||
|
||||
/**
|
||||
* Initializes variables used by the abstract converter
|
||||
*/
|
||||
AdvancedConverter(Map<String, String> inputArguments) {
|
||||
super(inputArguments.get("outputextension"));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String[] generateConversionCommand(String executable, File file, List<StreamObject> streams, String outFile) {
|
||||
List<String> command = FFMpegHelper.getFFMpegGeneralFileCommand(executable, file.getName());
|
||||
if (this.debug) {
|
||||
FFMpegHelper.addDebugArguments(command, 50, 120);
|
||||
}
|
||||
|
||||
if (!this.videoCodec.isEmpty()) {
|
||||
command.add("-vcodec");
|
||||
command.add(this.videoCodec);
|
||||
}
|
||||
|
||||
if (!this.pixelFormat.isEmpty()) {
|
||||
command.add("-pix_fmt");
|
||||
command.add(this.pixelFormat);
|
||||
}
|
||||
|
||||
if (this.audioSamplingFrequency > 0) {
|
||||
command.add("-ar");
|
||||
command.add("" + this.audioSamplingFrequency);
|
||||
}
|
||||
|
||||
if (this.moveHeaders) {
|
||||
command.add("-movflags");
|
||||
command.add("+faststart");
|
||||
}
|
||||
|
||||
//If the user wants to convert to an audio file, just select audio streams
|
||||
if (ListUtil.listContains(audioFormats, (item) -> item.equals(this.outputExtension)) || autoStreamSelection) {
|
||||
command.add(outFile);
|
||||
return command.toArray(new String[0]);
|
||||
}
|
||||
|
||||
if (!burnFirstAudio && !burnFirstSubtitle) {
|
||||
//Copy all streams
|
||||
command.add("-map");
|
||||
command.add("0");
|
||||
command.add("-c:a");
|
||||
command.add("copy");
|
||||
command.add("-c:s");
|
||||
command.add("copy");
|
||||
} else {
|
||||
|
||||
//Get the first audio stream in accordance with chosen languages
|
||||
List<AudioStream> audioStreams = filterAudioStreams(filterStreamsByType(streams, AudioStream.class), audioLanguages);
|
||||
AudioStream audioStream = getFirstAudioStream(new ArrayList<>(audioStreams));
|
||||
|
||||
//Get the first subtitle stream in accordance with chosen languages and signs and songs prevention
|
||||
List<SubtitleStream> subtitleStreams = filterSubtitleStreams(filterStreamsByType(streams,
|
||||
SubtitleStream.class), this.subtitleLanguages, this.preventPartialSubtitles);
|
||||
SubtitleStream subtitleStream = getFirstSubtitleStream(new ArrayList<>(subtitleStreams));
|
||||
|
||||
//Get the first video stream
|
||||
VideoStream videoStream = getFirstVideoStream(filterStreamsByType(streams, VideoStream.class));
|
||||
|
||||
//Add streams to output file
|
||||
if (burnFirstAudio) {
|
||||
FFMpegHelper.addAudioStream(command, audioStream, this.convertToStereo);
|
||||
} else {
|
||||
command.add("-map");
|
||||
command.add("0:a");
|
||||
command.add("-c:a");
|
||||
command.add("copy");
|
||||
}
|
||||
if (burnFirstSubtitle) {
|
||||
FFMpegHelper.addSubtitleAndVideoStream(command, subtitleStream, videoStream, file);
|
||||
} else {
|
||||
command.add("-map");
|
||||
command.add("0:s");
|
||||
command.add("-map");
|
||||
command.add("0:v");
|
||||
command.add("-c:s");
|
||||
command.add("copy");
|
||||
}
|
||||
}
|
||||
|
||||
command.add(outFile);
|
||||
return command.toArray(new String[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getValidFormats() {
|
||||
return ListUtil.concatenate(videoFormats, audioFormats);
|
||||
}
|
||||
}
|
@ -49,7 +49,7 @@ public class AnimeConverter extends AbstractConverter {
|
||||
|
||||
//Get the first audio stream in accordance with chosen languages
|
||||
List<AudioStream> audioStreams = filterAudioStreams(filterStreamsByType(streams, AudioStream.class), audioLanguages);
|
||||
AudioStream audioStream = getFirstAudioSteam(new ArrayList<>(audioStreams));
|
||||
AudioStream audioStream = getFirstAudioStream(new ArrayList<>(audioStreams));
|
||||
|
||||
//Get the first subtitle stream in accordance with chosen languages and signs and songs prevention
|
||||
List<SubtitleStream> subtitleStreams = filterSubtitleStreams(filterStreamsByType(streams,
|
||||
@ -57,7 +57,7 @@ public class AnimeConverter extends AbstractConverter {
|
||||
SubtitleStream subtitleStream = getFirstSubtitleStream(new ArrayList<>(subtitleStreams));
|
||||
|
||||
//Get the first video stream
|
||||
VideoStream videoStream = getFirstVideoStream(streams);
|
||||
VideoStream videoStream = getFirstVideoStream(filterStreamsByType(streams, VideoStream.class));
|
||||
|
||||
//Add streams to output file
|
||||
FFMpegHelper.addAudioStream(command, audioStream, toStereo);
|
||||
|
@ -33,7 +33,7 @@ public class AudioConverter extends AbstractConverter {
|
||||
}
|
||||
|
||||
//Gets the first audio stream from the file and adds it to the output file
|
||||
AudioStream audioStream = getFirstAudioSteam(streams);
|
||||
AudioStream audioStream = getFirstAudioStream(filterStreamsByType(streams, AudioStream.class));
|
||||
FFMpegHelper.addAudioStream(command, audioStream, false);
|
||||
command.add(outFile);
|
||||
|
||||
|
@ -0,0 +1,64 @@
|
||||
package net.knarcraft.ffmpegconverter.converter;
|
||||
|
||||
import net.knarcraft.ffmpegconverter.utility.FileUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* The ConverterProfiles class is responsible for loading and retrieving settings for a converter
|
||||
*/
|
||||
public class ConverterProfiles {
|
||||
|
||||
private Map<String, Map<String, String>> loadedProfiles;
|
||||
|
||||
/**
|
||||
* Instantiates a new converter profiles object
|
||||
*/
|
||||
public ConverterProfiles() {
|
||||
loadedProfiles = new HashMap<>();
|
||||
try {
|
||||
loadProfiles();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all available converter profiles as a set
|
||||
* @return <p>A set of all loaded converter profiles.</p>
|
||||
*/
|
||||
public Set<String> getProfiles() {
|
||||
return loadedProfiles.keySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all profile settings for the given converter profile
|
||||
* @param profileName <p>The name of the converter profile to get settings for.</p>
|
||||
* @return <p>Settings for the converter profile.</p>
|
||||
*/
|
||||
public Map<String, String> getProfileSettings(String profileName) {
|
||||
return loadedProfiles.get(profileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all converter profiles
|
||||
* @throws IOException <p>If unable to read the converter profiles file.</p>
|
||||
*/
|
||||
private void loadProfiles() throws IOException {
|
||||
String[] profiles = FileUtil.readFileLines("converter_profiles.txt");
|
||||
for (String profile : profiles) {
|
||||
Map<String, String> profileSettings = new HashMap<>();
|
||||
String[] settings = profile.split("\\|");
|
||||
String profileName = settings[0];
|
||||
for (int i = 1; i < settings.length; i++) {
|
||||
String[] settingParts = settings[i].split(":");
|
||||
profileSettings.put(settingParts[0], settingParts[1]);
|
||||
}
|
||||
loadedProfiles.put(profileName, profileSettings);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -37,9 +37,9 @@ public class WebVideoConverter extends AbstractConverter {
|
||||
}
|
||||
|
||||
//Get first streams from the file
|
||||
SubtitleStream subtitleStream = getFirstSubtitleStream(streams);
|
||||
VideoStream videoStream = getFirstVideoStream(streams);
|
||||
AudioStream audioStream = getFirstAudioSteam(streams);
|
||||
SubtitleStream subtitleStream = getFirstSubtitleStream(filterStreamsByType(streams, SubtitleStream.class));
|
||||
VideoStream videoStream = getFirstVideoStream(filterStreamsByType(streams, VideoStream.class));
|
||||
AudioStream audioStream = getFirstAudioStream(filterStreamsByType(streams, AudioStream.class));
|
||||
|
||||
//Add streams to output
|
||||
FFMpegHelper.addSubtitleAndVideoStream(command, subtitleStream, videoStream, file);
|
||||
|
@ -8,7 +8,7 @@ import net.knarcraft.ffmpegconverter.utility.ListUtil;
|
||||
public class ConverterArgument {
|
||||
|
||||
private final String name;
|
||||
private final char shorthand;
|
||||
private final String shorthand;
|
||||
private final boolean valueRequired;
|
||||
private final ConverterArgumentValue valueType;
|
||||
|
||||
@ -19,7 +19,7 @@ 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, ConverterArgumentValue valueType) {
|
||||
public ConverterArgument(String name, String shorthand, boolean valueRequired, ConverterArgumentValue valueType) {
|
||||
this.name = name;
|
||||
this.shorthand = shorthand;
|
||||
this.valueRequired = valueRequired;
|
||||
@ -38,7 +38,7 @@ public class ConverterArgument {
|
||||
* Gets the argument shorthand
|
||||
* @return <p>The argument shorthand</p>
|
||||
*/
|
||||
public char getShorthand() {
|
||||
public String getShorthand() {
|
||||
return shorthand;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,46 @@
|
||||
package net.knarcraft.ffmpegconverter.parser;
|
||||
|
||||
import net.knarcraft.ffmpegconverter.utility.FileUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
class ConverterArgumentsLoader {
|
||||
|
||||
private List<ConverterArgument> converterArguments;
|
||||
|
||||
/**
|
||||
* Instantiates a new converter arguments loader and loads converter arguments
|
||||
*/
|
||||
ConverterArgumentsLoader() {
|
||||
this.converterArguments = new ArrayList<>();
|
||||
try {
|
||||
loadConverterArguments();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets loaded converter arguments
|
||||
* @return <p>The loaded converter arguments.</p>
|
||||
*/
|
||||
List<ConverterArgument> getConverterArguments() {
|
||||
return new ArrayList<>(this.converterArguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all converter arguments
|
||||
* @throws IOException <p>If unable to read the converter argument file.</p>
|
||||
*/
|
||||
private void loadConverterArguments() throws IOException {
|
||||
String[] arguments = FileUtil.readFileLines("converter_arguments.txt");
|
||||
for (String argument : arguments) {
|
||||
String[] argumentFields = argument.split("\\|");
|
||||
converterArguments.add(new ConverterArgument(argumentFields[0], argumentFields[1], Boolean.parseBoolean(argumentFields[2]),
|
||||
ConverterArgumentValue.valueOf(argumentFields[3])));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -36,7 +36,7 @@ public class SubtitleStream extends AbstractStream implements StreamObject {
|
||||
*
|
||||
* @return <p>The title of the subtitle stream.</p>
|
||||
*/
|
||||
private String getTitle() {
|
||||
public String getTitle() {
|
||||
return this.title;
|
||||
}
|
||||
|
||||
@ -87,8 +87,8 @@ public class SubtitleStream extends AbstractStream implements StreamObject {
|
||||
return false;
|
||||
}
|
||||
String titleLowercase = getTitle().toLowerCase();
|
||||
return !titleLowercase.matches("signs?[ &\\/a-z]+songs?") &&
|
||||
!titleLowercase.matches("songs?[ &\\/a-z]+signs?") &&
|
||||
!titleLowercase.matches("forced");
|
||||
return !titleLowercase.matches(".*signs?[ &/a-z]+songs?.*") &&
|
||||
!titleLowercase.matches(".*songs?[ &/a-z]+signs?.*") &&
|
||||
!titleLowercase.matches(".*forced.*");
|
||||
}
|
||||
}
|
@ -21,7 +21,7 @@ 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) {
|
||||
public static <T> T[] concatenate(T[] listA, T[] listB) {
|
||||
int listALength = listA.length;
|
||||
int listBLength = listB.length;
|
||||
@SuppressWarnings("unchecked")
|
||||
@ -53,7 +53,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(T[] list, Predicate<T> predicate) {
|
||||
for (T item : list) {
|
||||
if (predicate.test(item)) {
|
||||
return true;
|
||||
|
@ -56,8 +56,8 @@ public final class Parser {
|
||||
String argumentName = currentToken.substring(2);
|
||||
foundArguments = ListUtil.getMatching(converterArguments, (item) -> item.getName().equals(argumentName));
|
||||
} else if (currentToken.startsWith("-")) {
|
||||
char argumentShorthand = currentToken.substring(1).charAt(0);
|
||||
foundArguments = ListUtil.getMatching(converterArguments, (item) -> item.getShorthand() == argumentShorthand);
|
||||
String argumentShorthand = currentToken.substring(1);
|
||||
foundArguments = ListUtil.getMatching(converterArguments, (item) -> item.getShorthand().equals(argumentShorthand));
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unexpected value when not given an argument.");
|
||||
}
|
||||
|
15
src/main/resources/converter_arguments.txt
Normal file
15
src/main/resources/converter_arguments.txt
Normal file
@ -0,0 +1,15 @@
|
||||
14
|
||||
recursions|r|true|INT
|
||||
infile|i|true|STRING
|
||||
audiolang|al|true|COMMA_SEPARATED_LIST
|
||||
subtitlelang|sl|true|COMMA_SEPARATED_LIST
|
||||
tostereo|ts|false|BOOLEAN
|
||||
preventpartialsubtitles|p|false|BOOLEAN
|
||||
outext|o|true|STRING
|
||||
autostreamselection|as|false|BOOLEAN
|
||||
burnfirstsubtitle|bs|false|BOOLEAN
|
||||
burnfirstaudio|ba|false|BOOLEAN
|
||||
videocodec|vc|true|STRING
|
||||
pixelformat|pf|true|STRING
|
||||
audiosamplingfrequency|asf|true|INT
|
||||
moveheaders|m|false|BOOLEAN
|
5
src/main/resources/converter_profiles.txt
Normal file
5
src/main/resources/converter_profiles.txt
Normal file
@ -0,0 +1,5 @@
|
||||
4
|
||||
Anime|audiolang:jpn,0|subtitlelang:eng,0|tostereo:true|preventpartialsubtitles:true|outext:mp4|videocodec:h264|pixelformat:yuv420p|audiosampling:48000|moveheaders:true|burnfirstaudio:true|burnfirstsubtitle:true
|
||||
WebVideo|audiolang:*|subtitlelang:*|tostereo:true|preventpartialsubtitles:false|outext:|videocodec:h264|pixelformat:yuv420p|audiosampling:48000|moveheaders:true|burnfirstaudio:true|burnfirstsubtitle:true
|
||||
Video|audiolang:*|subtitlelang:*|tostereo:false|preventpartialsubtitles:false|outext:|videocodec:|pixelformat:|audiosampling:|moveheaders:true|burnfirstaudio:true|burnfirstsubtitle:true
|
||||
Audio|audiolang:*|subtitlelang:*|tostereo:false|preventpartialsubtitles:false|outext:|videocodec:|pixelformat:|audiosampling:|moveheaders:|burnfirstaudio:|burnfirstsubtitle:
|
@ -0,0 +1,14 @@
|
||||
package net.knarcraft.ffmpegconverter.parser;
|
||||
|
||||
import org.junit.Test;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class ConverterArgumentsLoaderTest {
|
||||
|
||||
@Test
|
||||
public void loadTest() {
|
||||
ConverterArgumentsLoader loader = new ConverterArgumentsLoader();
|
||||
assertEquals(14, loader.getConverterArguments().size());
|
||||
}
|
||||
|
||||
}
|
@ -18,9 +18,9 @@ public class ParserTest {
|
||||
@Before
|
||||
public void setUp() {
|
||||
validArguments = new ArrayList<>();
|
||||
validArguments.add(new ConverterArgument("anargument", 'a', true, ConverterArgumentValue.STRING));
|
||||
validArguments.add(new ConverterArgument("turnoff", 't', false, ConverterArgumentValue.BOOLEAN));
|
||||
validArguments.add(new ConverterArgument("turnon", 'o', false, ConverterArgumentValue.BOOLEAN));
|
||||
validArguments.add(new ConverterArgument("anargument", "a", true, ConverterArgumentValue.STRING));
|
||||
validArguments.add(new ConverterArgument("turnoff", "t", false, ConverterArgumentValue.BOOLEAN));
|
||||
validArguments.add(new ConverterArgument("turnon", "o", false, ConverterArgumentValue.BOOLEAN));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
Loading…
Reference in New Issue
Block a user