Adds a new converter for purely re-ordering and filtering streams
All checks were successful
KnarCraft/FFmpegConvert/pipeline/head This commit looks good
All checks were successful
KnarCraft/FFmpegConvert/pipeline/head This commit looks good
This commit is contained in:
parent
380a1b800a
commit
c3c89fcb75
@ -8,6 +8,7 @@ import net.knarcraft.ffmpegconverter.converter.DownScaleConverter;
|
||||
import net.knarcraft.ffmpegconverter.converter.MKVToMP4Transcoder;
|
||||
import net.knarcraft.ffmpegconverter.converter.MkvH264Converter;
|
||||
import net.knarcraft.ffmpegconverter.converter.MkvH265ReducedConverter;
|
||||
import net.knarcraft.ffmpegconverter.converter.StreamOrderConverter;
|
||||
import net.knarcraft.ffmpegconverter.converter.SubtitleEmbed;
|
||||
import net.knarcraft.ffmpegconverter.converter.VideoConverter;
|
||||
import net.knarcraft.ffmpegconverter.converter.WebAnimeConverter;
|
||||
@ -94,7 +95,8 @@ public class FFMpegConvert {
|
||||
7. MKV to MP4 transcoder
|
||||
8. DownScaleConverter
|
||||
9. mp4 Subtitle Embed
|
||||
10. Anime to h265 all streams""", 1, 10);
|
||||
10. Anime to h265 all streams
|
||||
11. Stream reorder""", 1, 11);
|
||||
|
||||
return switch (choice) {
|
||||
case 1 -> generateWebAnimeConverter();
|
||||
@ -107,6 +109,7 @@ public class FFMpegConvert {
|
||||
case 8 -> generateDownScaleConverter();
|
||||
case 9 -> new SubtitleEmbed(FFPROBE_PATH, FFMPEG_PATH);
|
||||
case 10 -> generateAnimeConverter();
|
||||
case 11 -> generateStreamOrderConverter();
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
@ -194,6 +197,34 @@ public class FFMpegConvert {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes and returns a stream reorder converter
|
||||
*
|
||||
* @return <p>The initialized stream order converter</p>
|
||||
*/
|
||||
@Nullable
|
||||
private static Converter generateStreamOrderConverter() {
|
||||
OutputUtil.println("Note that a * in the sort order matches any stream not yet matched, and 0 matches " +
|
||||
"undefined language streams. The subtitle name filter will include any streams with titles " +
|
||||
"containing the filter, but if it contains RegEx expressions, a RegEx match will be performed " +
|
||||
"instead.\nYour input: ");
|
||||
OutputUtil.println("<Audio sort order> <Subtitle sort order> [Subtitle name filter]");
|
||||
List<String> input = readInput(3);
|
||||
|
||||
if (input.size() < 2) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String audioLanguages = input.get(0);
|
||||
String subtitleLanguages = input.get(1);
|
||||
String subtitleNameFilter = "*";
|
||||
if (input.size() > 2) {
|
||||
subtitleNameFilter = input.get(2);
|
||||
}
|
||||
|
||||
return new StreamOrderConverter(FFPROBE_PATH, FFMPEG_PATH, audioLanguages, subtitleLanguages, subtitleNameFilter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes and returns the anime converter
|
||||
*
|
||||
|
@ -0,0 +1,129 @@
|
||||
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;
|
||||
import net.knarcraft.ffmpegconverter.converter.module.DebugModule;
|
||||
import net.knarcraft.ffmpegconverter.converter.module.ModuleExecutor;
|
||||
import net.knarcraft.ffmpegconverter.converter.module.mapping.MapAllModule;
|
||||
import net.knarcraft.ffmpegconverter.converter.module.mapping.SetDefaultStreamModule;
|
||||
import net.knarcraft.ffmpegconverter.converter.module.output.CopyAudioModule;
|
||||
import net.knarcraft.ffmpegconverter.converter.module.output.CopySubtitlesModule;
|
||||
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.SetStreamLanguageModule;
|
||||
import net.knarcraft.ffmpegconverter.converter.sorter.AudioLanguageSorter;
|
||||
import net.knarcraft.ffmpegconverter.converter.sorter.MinimalSubtitleSorter;
|
||||
import net.knarcraft.ffmpegconverter.converter.sorter.SpecialAudioSorter;
|
||||
import net.knarcraft.ffmpegconverter.converter.sorter.StreamSorter;
|
||||
import net.knarcraft.ffmpegconverter.converter.sorter.SubtitleLanguageSorter;
|
||||
import net.knarcraft.ffmpegconverter.converter.sorter.SubtitleTitleSorter;
|
||||
import net.knarcraft.ffmpegconverter.property.MinimalSubtitlePreference;
|
||||
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;
|
||||
|
||||
/**
|
||||
* A converter for converting anime, keeping all streams
|
||||
*/
|
||||
public class StreamOrderConverter extends AbstractConverter {
|
||||
|
||||
private final List<String> audioLanguages;
|
||||
private final List<String> subtitleLanguages;
|
||||
private final MinimalSubtitlePreference subtitlePreference;
|
||||
private final String subtitleNameFilter;
|
||||
|
||||
/**
|
||||
* Instantiates a new anime converter
|
||||
*
|
||||
* @param ffprobePath <p>Path/command to ffprobe.</p>
|
||||
* @param ffmpegPath <p>Path/command to ffmpeg.</p>
|
||||
* @param audioLanguages <p>The language priority for languages</p>
|
||||
* @param subtitleLanguages <p>The language priority for subtitles</p>
|
||||
*/
|
||||
public StreamOrderConverter(@NotNull String ffprobePath, @NotNull String ffmpegPath,
|
||||
@NotNull String audioLanguages, @NotNull String subtitleLanguages,
|
||||
@NotNull String subtitleNameFilter) {
|
||||
super("mkv");
|
||||
Configuration configuration = FFMpegConvert.getConfiguration();
|
||||
this.ffprobePath = ffprobePath;
|
||||
this.ffmpegPath = ffmpegPath;
|
||||
this.audioLanguages = List.of(audioLanguages.split(","));
|
||||
this.subtitleLanguages = List.of(subtitleLanguages.split(","));
|
||||
this.subtitlePreference = configuration.getMinimalSubtitlePreference();
|
||||
this.subtitleNameFilter = subtitleNameFilter;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public FFMpegCommand generateConversionCommand(@NotNull String executable,
|
||||
@NotNull StreamProbeResult probeResult,
|
||||
@NotNull String outFile) {
|
||||
FFMpegCommand command = FFMpegHelper.getFFMpegGeneralFileCommand(executable, probeResult.parsedFiles());
|
||||
List<ConverterModule> modules = new ArrayList<>();
|
||||
if (this.debug) {
|
||||
modules.add(new DebugModule(90, 120));
|
||||
}
|
||||
modules.add(new FastStartModule());
|
||||
|
||||
//Map all video streams
|
||||
List<VideoStream> videoStreams = probeResult.getVideoStreams();
|
||||
modules.add(new MapAllModule<>(videoStreams));
|
||||
setOutputIndexes(videoStreams);
|
||||
|
||||
//Get the first audio stream in accordance with chosen languages
|
||||
StreamSorter<AudioStream> audioSorter = new AudioLanguageSorter(this.audioLanguages)
|
||||
.append(new SpecialAudioSorter(MinimalSubtitlePreference.REJECT));
|
||||
List<AudioStream> 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<SubtitleStream> subtitleSorter = new SubtitleTitleSorter(
|
||||
List.of(this.subtitleNameFilter.split(",")))
|
||||
.append(new SubtitleLanguageSorter(this.subtitleLanguages))
|
||||
.append(new MinimalSubtitleSorter(this.subtitlePreference));
|
||||
List<SubtitleStream> 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()));
|
||||
|
||||
for (AudioStream audioStream : sortedAudio) {
|
||||
modules.add(new CopyAudioModule(audioStream));
|
||||
}
|
||||
modules.add(new CopySubtitlesModule());
|
||||
modules.add(new CopyVideoModule());
|
||||
|
||||
// Map all attached streams, such as fonts and covers
|
||||
modules.add(new MapAllModule<>(probeResult.getOtherStreams()));
|
||||
|
||||
modules.add(new SetOutputFileModule(outFile));
|
||||
|
||||
new ModuleExecutor(command, modules).execute();
|
||||
return command;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public List<String> getValidFormats() {
|
||||
return this.videoFormats;
|
||||
}
|
||||
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
package net.knarcraft.ffmpegconverter.converter.sorter;
|
||||
|
||||
import net.knarcraft.ffmpegconverter.FFMpegConvert;
|
||||
import net.knarcraft.ffmpegconverter.streams.SubtitleStream;
|
||||
import net.knarcraft.ffmpegconverter.utility.OutputUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@ -45,17 +45,15 @@ public class SubtitleTitleSorter extends AbstractSorter<SubtitleStream> {
|
||||
|
||||
boolean isRegEx = isValidRegularExpression(filter) && hasSpecialRegexCharacters(filter);
|
||||
|
||||
if (FFMpegConvert.getConfiguration().isDebugEnabled()) {
|
||||
System.out.println("Filtering subtitles by filter " + filter + ". RegEx is " + isRegEx);
|
||||
}
|
||||
OutputUtil.printDebug("Filtering subtitles by filter " + filter + ". RegEx is " + isRegEx);
|
||||
|
||||
for (SubtitleStream subtitleStream : input) {
|
||||
String title = subtitleStream.getTitle().trim().toLowerCase();
|
||||
// Add the subtitle if the filter matches, and it hasn't been added already
|
||||
boolean matches = filter.trim().equals("*") || (isRegEx && title.matches(filter)) ||
|
||||
(!isRegEx && title.contains(filter));
|
||||
boolean matches = filter.trim().equals("*") || (isRegEx && title.matches(filter.toLowerCase())) ||
|
||||
(!isRegEx && title.contains(filter.toLowerCase()));
|
||||
if (matches && !output.contains(subtitleStream)) {
|
||||
System.out.println("Subtitle stream with title " + title + " matches");
|
||||
OutputUtil.printDebug("Subtitle stream with title " + title + " matches");
|
||||
output.add(subtitleStream);
|
||||
}
|
||||
}
|
||||
|
@ -50,17 +50,8 @@ public class SubtitleStream extends AbstractStream implements StreamObject {
|
||||
* @return <p>True if the subtitle translates everything.</p>
|
||||
*/
|
||||
private boolean checkIfIsFullSubtitle() {
|
||||
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.*") &&
|
||||
!titleLowercase.matches(".*s&s.*") &&
|
||||
!titleLowercase.matches("signs?") &&
|
||||
!titleLowercase.matches("songs?") &&
|
||||
!titleLowercase.matches(".*signs only.*") &&
|
||||
!titleLowercase.matches(".* signs .*") &&
|
||||
!titleLowercase.matches("signs@.*") &&
|
||||
!titleLowercase.matches("signs -.*");
|
||||
return !getTitle().toLowerCase().trim().matches(".*si(ng|gn)s?[ &/a-z+]+(songs?)?([$ @-]+.*)?|" +
|
||||
".*songs?[ &/a-z]+(si(gn|ng)s?)?([$ @-]+.*)?|.*forced.*|.*s&s.*|songs($| |-|@)+|si(gn|ng)s($| |-|@)+");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
Loading…
Reference in New Issue
Block a user