diff --git a/src/main/java/net/knarcraft/ffmpegconverter/converter/AbstractConverter.java b/src/main/java/net/knarcraft/ffmpegconverter/converter/AbstractConverter.java
index b987af0..b82118b 100644
--- a/src/main/java/net/knarcraft/ffmpegconverter/converter/AbstractConverter.java
+++ b/src/main/java/net/knarcraft/ffmpegconverter/converter/AbstractConverter.java
@@ -48,7 +48,8 @@ public abstract class AbstractConverter implements Converter {
@Override
public void convert(@NotNull File file) throws IOException {
- StreamProbeResult probeResult = FFMpegHelper.probeFile(this.ffprobePath, file, this.subtitleFormats);
+ StreamProbeResult probeResult = FFMpegHelper.probeFile(this.ffprobePath, file, this.subtitleFormats,
+ this.audioFormats);
if (probeResult.parsedStreams().isEmpty()) {
throw new IllegalArgumentException("The file has no valid streams. Please make sure the file exists and" +
" is not corrupt.");
diff --git a/src/main/java/net/knarcraft/ffmpegconverter/property/StreamType.java b/src/main/java/net/knarcraft/ffmpegconverter/property/StreamType.java
new file mode 100644
index 0000000..23d5062
--- /dev/null
+++ b/src/main/java/net/knarcraft/ffmpegconverter/property/StreamType.java
@@ -0,0 +1,28 @@
+package net.knarcraft.ffmpegconverter.property;
+
+/**
+ * A representation of different stream types
+ */
+public enum StreamType {
+
+ /**
+ * A video stream
+ */
+ VIDEO,
+
+ /**
+ * An audio stream
+ */
+ AUDIO,
+
+ /**
+ * A subtitle stream
+ */
+ SUBTITLE,
+
+ /**
+ * None of the above
+ */
+ OTHER
+
+}
diff --git a/src/main/java/net/knarcraft/ffmpegconverter/streams/SubtitleStream.java b/src/main/java/net/knarcraft/ffmpegconverter/streams/SubtitleStream.java
index 7fa296e..97709f9 100644
--- a/src/main/java/net/knarcraft/ffmpegconverter/streams/SubtitleStream.java
+++ b/src/main/java/net/knarcraft/ffmpegconverter/streams/SubtitleStream.java
@@ -50,7 +50,7 @@ public class SubtitleStream extends AbstractStream implements StreamObject {
* @return
True if the subtitle translates everything.
*/
private boolean isFullSubtitle() {
- String titleLowercase = getTitle().toLowerCase();
+ String titleLowercase = getTitle().toLowerCase().trim();
return !titleLowercase.matches(".*si(ng|gn)s?[ &/a-z]+songs?.*") &&
!titleLowercase.matches(".*songs?[ &/a-z]+si(gn|ng)s?.*") &&
!titleLowercase.matches(".*forced.*") &&
diff --git a/src/main/java/net/knarcraft/ffmpegconverter/utility/FFMpegHelper.java b/src/main/java/net/knarcraft/ffmpegconverter/utility/FFMpegHelper.java
index 1958052..8dd5e86 100644
--- a/src/main/java/net/knarcraft/ffmpegconverter/utility/FFMpegHelper.java
+++ b/src/main/java/net/knarcraft/ffmpegconverter/utility/FFMpegHelper.java
@@ -3,6 +3,7 @@ package net.knarcraft.ffmpegconverter.utility;
import net.knarcraft.ffmpegconverter.container.FFMpegCommand;
import net.knarcraft.ffmpegconverter.container.ProcessResult;
import net.knarcraft.ffmpegconverter.container.StreamProbeResult;
+import net.knarcraft.ffmpegconverter.property.StreamType;
import net.knarcraft.ffmpegconverter.streams.AudioStream;
import net.knarcraft.ffmpegconverter.streams.OtherStream;
import net.knarcraft.ffmpegconverter.streams.StreamObject;
@@ -73,13 +74,15 @@ public final class FFMpegHelper {
* @param ffprobePath The path/command to ffprobe
* @param file The file to probe
* @param subtitleFormats The extensions to accept for external subtitles
+ * @param audioFormats The extensions to accept for external audio files
* @return A list of StreamObjects
* @throws IOException If the process can't be readProcess
*/
@NotNull
public static StreamProbeResult probeFile(@NotNull String ffprobePath, @NotNull File file,
- @NotNull List subtitleFormats) throws IOException {
- return parseStreams(ffprobePath, probeForStreams(ffprobePath, file), file, subtitleFormats);
+ @NotNull List subtitleFormats,
+ @NotNull List audioFormats) throws IOException {
+ return parseStreams(ffprobePath, probeForStreams(ffprobePath, file), file, subtitleFormats, audioFormats);
}
/**
@@ -284,11 +287,27 @@ public final class FFMpegHelper {
* @param streams A list of all streams for the current file.
* @param file The file currently being converted.
* @param subtitleFormats The extensions to accept for external subtitles
+ * @param audioFormats The extensions to accept for external audio tracks
* @return A list of StreamObjects.
*/
@NotNull
private static StreamProbeResult parseStreams(@NotNull String ffprobePath, @NotNull List streams,
- @NotNull File file, @NotNull List subtitleFormats) throws IOException {
+ @NotNull File file, @NotNull List subtitleFormats,
+ @NotNull List audioFormats) throws IOException {
+ StreamProbeResult probeResult = new StreamProbeResult(new ArrayList<>(List.of(file)), parseStreamObjects(streams));
+ getExternalStreams(probeResult, ffprobePath, file.getParentFile(), file.getName(), subtitleFormats);
+ getExternalStreams(probeResult, ffprobePath, file.getParentFile(), file.getName(), audioFormats);
+ return probeResult;
+ }
+
+ /**
+ * Parses the stream objects found in the given streams
+ *
+ * @param streams The stream data to parse
+ * @return The parsed stream objects
+ */
+ @NotNull
+ private static List parseStreamObjects(@NotNull List streams) {
List parsedStreams = new ArrayList<>();
int relativeAudioIndex = 0;
int relativeVideoIndex = 0;
@@ -297,30 +316,50 @@ public final class FFMpegHelper {
for (String stream : streams) {
String[] streamParts = stream.split(PROBE_SPLIT_CHARACTER);
Map streamInfo = getStreamInfo(streamParts);
+ StreamType streamType = getStreamType(streamInfo);
- String codecType = ValueParsingHelper.parseString(streamInfo.get(StreamTag.CODEC_TYPE), "");
- switch (codecType) {
- case "video":
- // Some attached covers are marked as video streams
- if (ValueParsingHelper.parseInt(streamInfo.get(StreamTag.DISPOSITION_ATTACHED_PIC), 0) != 1) {
- parsedStreams.add(new VideoStream(streamInfo, 0, relativeVideoIndex++));
- } else {
- parsedStreams.add(new OtherStream(streamInfo, 0));
- }
+ switch (streamType) {
+ case VIDEO:
+ parsedStreams.add(new VideoStream(streamInfo, 0, relativeVideoIndex++));
break;
- case "audio":
+ case AUDIO:
parsedStreams.add(new AudioStream(streamInfo, 0, relativeAudioIndex++));
break;
- case "subtitle":
+ case SUBTITLE:
parsedStreams.add(new SubtitleStream(streamInfo, 0, relativeSubtitleIndex++));
break;
- default:
+ case OTHER:
parsedStreams.add(new OtherStream(streamInfo, 0));
+ break;
}
}
- StreamProbeResult probeResult = new StreamProbeResult(List.of(file), parsedStreams);
- getExternalSubtitles(probeResult, ffprobePath, file.getParentFile(), file.getName(), subtitleFormats);
- return probeResult;
+ return parsedStreams;
+ }
+
+ /**
+ * Gets the type of a stream from its stream info
+ *
+ * @param streamInfo The information describing the stream
+ * @return The type of the stream
+ */
+ @NotNull
+ private static StreamType getStreamType(@NotNull Map streamInfo) {
+ String codecType = ValueParsingHelper.parseString(streamInfo.get(StreamTag.CODEC_TYPE), "");
+ switch (codecType) {
+ case "video":
+ // Some attached covers are marked as video streams
+ if (ValueParsingHelper.parseInt(streamInfo.get(StreamTag.DISPOSITION_ATTACHED_PIC), 0) != 1) {
+ return StreamType.VIDEO;
+ } else {
+ return StreamType.OTHER;
+ }
+ case "audio":
+ return StreamType.AUDIO;
+ case "subtitle":
+ return StreamType.SUBTITLE;
+ default:
+ return StreamType.OTHER;
+ }
}
/**
@@ -337,52 +376,64 @@ public final class FFMpegHelper {
continue;
}
String[] keyValue = part.split("=");
+ String value = keyValue.length > 1 ? keyValue[1] : "";
+
StreamTag tag = StreamTag.getFromString(keyValue[0]);
if (tag != null) {
- streamInfo.put(tag, keyValue[1]);
+ streamInfo.put(tag, value);
}
}
return streamInfo;
}
/**
- * Tries to find any external subtitles adjacent to the first input file, and appends it to the given probe result
+ * Tries to find any external files adjacent to the first input file, and appends it to the given probe result
*
* @param streamProbeResult The stream probe result to append to
* @param ffprobePath The path/command to ffprobe
* @param directory The directory containing the file
* @param convertingFile The first/main file to be converted
- * @param subtitleFormats The extensions to accept for external subtitles
+ * @param formats The extensions to accept for external tracks
*/
- private static void getExternalSubtitles(@NotNull StreamProbeResult streamProbeResult,
- @NotNull String ffprobePath, @NotNull File directory,
- @NotNull String convertingFile, @NotNull List subtitleFormats) throws IOException {
+ private static void getExternalStreams(@NotNull StreamProbeResult streamProbeResult,
+ @NotNull String ffprobePath, @NotNull File directory,
+ @NotNull String convertingFile,
+ @NotNull List formats) throws IOException {
//Find all files in the same directory with external subtitle formats
- File[] subtitleFiles = FileUtil.listFilesRecursive(directory, subtitleFormats, 1);
- // TODO: Generalize this for external audio tracks
+ File[] files = FileUtil.listFilesRecursive(directory, formats, 1);
//Return early if no files were found
- if (subtitleFiles == null) {
+ if (files == null) {
return;
}
String fileTitle = FileUtil.stripExtension(convertingFile);
- List subtitleFilesList = new ArrayList<>(Arrays.asList(subtitleFiles));
+ List filesList = new ArrayList<>(Arrays.asList(files));
//Finds the files which are subtitles probably belonging to the file
- subtitleFilesList = ListUtil.getMatching(subtitleFilesList,
- (subtitleFile) -> subtitleFile.getName().contains(fileTitle));
+ filesList = ListUtil.getMatching(filesList, (file) -> file.getName().contains(fileTitle));
- for (File subtitleFile : subtitleFilesList) {
+ for (File file : filesList) {
int inputIndex = streamProbeResult.parsedFiles().size();
- streamProbeResult.parsedFiles().add(subtitleFile);
+ streamProbeResult.parsedFiles().add(file);
//Probe the files and add them to the result list
- List streams = probeForStreams(ffprobePath, subtitleFile);
- int relativeIndex = 0;
+ List streams = probeForStreams(ffprobePath, file);
+
+ int audioIndex = 0;
+ int subtitleIndex = 0;
+ int videoIndex = 0;
for (String stream : streams) {
String[] streamParts = stream.split(PROBE_SPLIT_CHARACTER);
Map streamInfo = getStreamInfo(streamParts);
- streamProbeResult.parsedStreams().add(new SubtitleStream(streamInfo, inputIndex, relativeIndex++));
+ StreamObject streamObject = null;
+ switch (getStreamType(streamInfo)) {
+ case SUBTITLE -> streamObject = new SubtitleStream(streamInfo, inputIndex, subtitleIndex++);
+ case AUDIO -> streamObject = new AudioStream(streamInfo, inputIndex, audioIndex++);
+ case VIDEO -> streamObject = new VideoStream(streamInfo, inputIndex, videoIndex++);
+ }
+ if (streamObject != null) {
+ streamProbeResult.parsedStreams().add(streamObject);
+ }
}
}
}