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.hardwarecoding.HardwareDecodeModule; import net.knarcraft.ffmpegconverter.converter.module.mapping.AddStereoAudioStreamModule; import net.knarcraft.ffmpegconverter.converter.module.mapping.BurnSubtitleModule; import net.knarcraft.ffmpegconverter.converter.module.mapping.SelectSingleStreamModule; import net.knarcraft.ffmpegconverter.converter.module.output.SetOutputFileModule; import net.knarcraft.ffmpegconverter.converter.sorter.AudioLanguageSorter; import net.knarcraft.ffmpegconverter.converter.sorter.MinimalSubtitleSorter; 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 org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; import static net.knarcraft.ffmpegconverter.utility.FFMpegHelper.getNthSteam; /** * A converter mainly designed for converting anime to web-playable mp4 */ public class WebAnimeConverter extends AbstractConverter { private final List audioLanguages; private final List subtitleLanguages; private final boolean toStereo; private final MinimalSubtitlePreference subtitlePreference; private final int forcedAudioIndex; private final int forcedSubtitleIndex; private final String subtitleNameFilter; /** * Instantiates a new anime converter * * @param ffprobePath

Path/command to ffprobe.

* @param ffmpegPath

Path/command to ffmpeg.

* @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, 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 = configuration.getAnimeAudioLanguages(); this.subtitleLanguages = configuration.getAnimeSubtitleLanguages(); this.toStereo = toStereo; this.subtitlePreference = subtitlePreference; this.forcedAudioIndex = forcedAudioIndex; this.forcedSubtitleIndex = forcedSubtitleIndex; this.subtitleNameFilter = subtitleNameFilter; } @Override @Nullable public FFMpegCommand generateConversionCommand(@NotNull String executable, @NotNull StreamProbeResult probeResult, @NotNull String outFile) { FFMpegCommand command = FFMpegHelper.getFFMpegWebVideoCommand(executable, probeResult.parsedFiles()); List modules = new ArrayList<>(); if (this.debug) { modules.add(new DebugModule(0, 0)); } //Get the first audio stream in accordance with chosen languages AudioStream audioStream = getNthSteam(new AudioLanguageSorter(this.audioLanguages).sort( probeResult.getAudioStreams()), this.forcedAudioIndex); if (audioStream == null) { throw new IllegalArgumentException("The given input resulted in no audio stream being selected"); } if (this.toStereo) { modules.add(new AddStereoAudioStreamModule(audioStream, true)); } else { modules.add(new SelectSingleStreamModule(audioStream)); } //Get the first video stream VideoStream videoStream = getNthSteam(probeResult.getVideoStreams(), 0); //Get the first subtitle stream in accordance with chosen languages and signs and songs prevention StreamSorter subtitleSorter = new SubtitleTitleSorter(List.of(this.subtitleNameFilter)) .append(new MinimalSubtitleSorter(this.subtitlePreference)) .append(new SubtitleLanguageSorter(this.subtitleLanguages)); SubtitleStream subtitleStream = getNthSteam(subtitleSorter.chainSort(probeResult.getSubtitleStreams()), this.forcedSubtitleIndex); modules.add(new HardwareDecodeModule()); if (subtitleStream != null && videoStream != null) { modules.add(new BurnSubtitleModule(subtitleStream, videoStream, true)); } else if (videoStream != null) { modules.add(new SelectSingleStreamModule(videoStream)); } else { throw new IllegalArgumentException("The selected video stream does not exist!"); } modules.add(new SetOutputFileModule(outFile)); new ModuleExecutor(command, modules).execute(); return command; } @Override @NotNull public List getValidFormats() { return this.videoFormats; } }