package info.toyonos.subtitles4j.helper; import info.toyonos.subtitles4j.factory.Subtitles4jException; import info.toyonos.subtitles4j.factory.Subtitles4jFactory; import info.toyonos.subtitles4j.factory.SubtitlesType; import info.toyonos.subtitles4j.model.SubtitlesContainer; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import org.apache.commons.io.FilenameUtils; public class Subtitles4jUtils { private static final SubtitlesContainerProcessing SHIFTING_PROCESSING = new SubtitlesContainerProcessing() { @Override public void process(SubtitlesContainer container, Object... params) { container.shiftTime((Integer) params[0]); } }; private static final SubtitlesContainerProcessing REMOVING_PROCESSING = new SubtitlesContainerProcessing() { @Override public void process(SubtitlesContainer container, Object... params) { container.remove((String) params[0], (Boolean) params[1]); } }; /** * Extract the <code>SubtitlesType</code> from a <code>File</code>, based on its extension * @param subtitlesFile the input <code>File</code> * @return the matching <code>SubtitlesType</code> or null if not supported */ public static SubtitlesType getType(String subtitlesFileName) { String ext = FilenameUtils.getExtension(subtitlesFileName); return SubtitlesType.fromExtension(ext); } /** * <p>Shift the timestamps of an input subtitles stream</p> * <p>It can be done in both ways, adding or removing milliseconds. If a timestamp become lower than zero, it is set to zero.</p> * @param input the <code>InputStream</code> on the subtitles source * @param inputType the <code>SubtitlesType</code> of the input * @param output the <code>OutputStream</code> containing the modified subtitles * @param millis the time in millisecond to be added to each caption, can be negative * @return the <code>OutputStream</code> containing the modified subtitles * @throws Subtitles4jException if an error occurs during the operation * @throws IOException if any IO error occurs */ public static OutputStream shift(InputStream input, SubtitlesType inputType, OutputStream output, int millis) throws Subtitles4jException, IOException { return transformSubtitles(input, inputType, output, SHIFTING_PROCESSING, millis); } /** * <p>Shift the timestamps of an input subtitles file</p> * <p>It can be done in both ways, adding or removing milliseconds. If a timestamp become lower than zero, it is set to zero.</p> * @param input the input subtitles <code>File</code> * @param millis the time in millisecond to be added to each caption, can be negative * @return the modified <code>File</code>, which is the same as the input * @throws Subtitles4jException if an error occurs during the operation * @throws IOException if any IO error occurs */ public static File shift(File input, int millis) throws Subtitles4jException, IOException { return transformSubtitles(input, SHIFTING_PROCESSING, millis); } /** * <p>Remove all the captions containing the specified regular expression, from an input subtitles stream</p> * <p>For each caption, the search is performed on each line. A match on at least one line is enough to remove the caption</p> * @param input the <code>InputStream</code> on the subtitles source * @param inputType the <code>SubtitlesType</code> of the input * @param output the <code>OutputStream</code> containing the modified subtitles * @param regex the regular expression to which captions are to be matched * @param caseSensitive true for a case sensitive operation, false otherwise * @return the <code>OutputStream</code> containing the modified subtitles * @throws Subtitles4jException if an error occurs during the operation * @throws IOException if any IO error occurs */ private static OutputStream removeCaptions(InputStream input, SubtitlesType inputType, OutputStream output, String regex, boolean caseSensitive) throws Subtitles4jException, IOException { return transformSubtitles(input, inputType, output, REMOVING_PROCESSING, regex, caseSensitive); } /** * Equivalent to {@link #removeCaptions(InputStream, SubtitlesType, OutputStream, String, boolean)} for a case sensitive search */ public static OutputStream removeCaptions(InputStream input, SubtitlesType inputType, OutputStream output, String regex) throws Subtitles4jException, IOException { return removeCaptions(input, inputType, output, regex, true); } /** * Equivalent to {@link #removeCaptions(InputStream, SubtitlesType, OutputStream, String, boolean)} for a case insensitive search */ public static OutputStream removeCaptionsIgnoreCase(InputStream input, SubtitlesType inputType, OutputStream output, String regex) throws Subtitles4jException, IOException { return removeCaptions(input, inputType, output, regex, false); } /** * <p>Remove all the captions containing the specified regular expression, from an input subtitles file</p> * <p>For each caption, the search is performed on each line. A match on at least one line is enough to remove the caption</p> * @param input the input subtitles <code>File</code> * @param regex the regular expression to which captions are to be matched * @param caseSensitive true for a case sensitive operation, false otherwise * @return the modified <code>File</code>, which is the same as the input * @throws Subtitles4jException if an error occurs during the operation * @throws IOException if any IO error occurs */ private static File removeCaptions(File input, String regex, boolean caseSensitive) throws Subtitles4jException, IOException { return transformSubtitles(input, REMOVING_PROCESSING, regex, caseSensitive); } /** * Equivalent to {@link #removeCaptions(File, String, boolean)} for a case sensitive search */ public static File removeCaptions(File input, String regex) throws Subtitles4jException, IOException { return removeCaptions(input, regex, true); } /** * Equivalent to {@link #removeCaptions(File, String, boolean)} for a case insensitive search */ public static File removeCaptionsIgnoreCase(File input, String regex) throws Subtitles4jException, IOException { return removeCaptions(input, regex, false); } /** * Do a certain operation on an input subtitles stream * @param input the <code>InputStream</code> on the subtitles source * @param inputType the <code>SubtitlesType</code> of the input * @param output the <code>OutputStream</code> containing the modified subtitles * @param processing the processing to apply * @param params the optional parameters * @return the <code>OutputStream</code> containing the modified subtitles * @throws Subtitles4jException if an error occurs during the operation * @throws IOException if any IO error occurs */ private static OutputStream transformSubtitles(InputStream input, SubtitlesType inputType, OutputStream output, SubtitlesContainerProcessing processing, Object... params) throws Subtitles4jException, IOException { Subtitles4jFactory factory = Subtitles4jFactory.getInstance(); SubtitlesContainer container = factory.fromStream(input, inputType); processing.process(container, params); return factory.toSubtitlesType(container, output, inputType); } /** * Do a certain operation on an input subtitles file * @param input the input subtitles <code>File</code> * @param processing the processing to apply * @param params the optional parameters * @return the modified <code>File</code>, which is the same as the input * @throws Subtitles4jException if an error occurs during the operation * @throws IOException if any IO error occurs */ private static File transformSubtitles(File input, SubtitlesContainerProcessing processing, Object... params) throws Subtitles4jException, IOException { Subtitles4jFactory factory = Subtitles4jFactory.getInstance(); SubtitlesContainer container = factory.fromFile(input); processing.process(container, params); return factory.toSubtitlesType(container, input, getType(input.getName())); } /** * This interface defines a processing on a <code>SubtitlesContainer</code> */ private interface SubtitlesContainerProcessing { /** * Do a certain operation on a <code>SubtitlesContainer</code> * @param container The <code>SubtitlesContainer</code> to treat * @param params the optional parameters */ void process(SubtitlesContainer container, Object... params); } }