/**
* Licensed to The Apereo Foundation under one or more contributor license
* agreements. See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
*
* The Apereo Foundation licenses this file to you under the Educational
* Community License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of the License
* at:
*
* http://opensource.org/licenses/ecl2.txt
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*
*/
package org.opencastproject.caption.converters;
import org.opencastproject.caption.api.Caption;
import org.opencastproject.caption.api.CaptionConverter;
import org.opencastproject.caption.api.CaptionConverterException;
import org.opencastproject.caption.api.IllegalTimeFormatException;
import org.opencastproject.caption.api.Time;
import org.opencastproject.caption.impl.CaptionImpl;
import org.opencastproject.caption.impl.TimeImpl;
import org.opencastproject.caption.util.TimeUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
/**
* Converter engine for SubRip srt caption format. It does not support advanced SubRip format (SubRip format with
* annotations). Advanced format will be parsed but all annotations will be stripped off.
*
*/
public class SubRipCaptionConverter implements CaptionConverter {
/** Logging utility */
private static final Logger logger = LoggerFactory.getLogger(SubRipCaptionConverter.class);
private static final String EXTENSION = "srt";
/** line ending used in srt - windows native in specification */
private static final String LINE_ENDING = "\r\n";
/**
* {@inheritDoc} Since srt does not store information about language, language parameter is ignored.
*
* @see org.opencastproject.caption.api.CaptionConverter#importCaption(java.io.InputStream, java.lang.String)
*/
@Override
public List<Caption> importCaption(InputStream in, String language) throws CaptionConverterException {
List<Caption> collection = new ArrayList<Caption>();
// initialize scanner object
Scanner scanner = new Scanner(in, "UTF-8");
scanner.useDelimiter("[\n(\r\n)]{2}");
// create initial time
Time time = null;
try {
time = new TimeImpl(0, 0, 0, 0);
} catch (IllegalTimeFormatException e1) {
}
while (scanner.hasNext()) {
String captionString = scanner.next();
// convert line endings to \n
captionString = captionString.replace("\r\n", "\n");
// split to number, time and caption
String[] captionParts = captionString.split("\n", 3);
// check for table length
if (captionParts.length != 3) {
throw new CaptionConverterException("Invalid caption for SubRip format: " + captionString);
}
// get time part
String[] timePart = captionParts[1].split("-->");
// parse time
Time inTime;
Time outTime;
try {
inTime = TimeUtil.importSrt(timePart[0].trim());
outTime = TimeUtil.importSrt(timePart[1].trim());
} catch (IllegalTimeFormatException e) {
throw new CaptionConverterException(e.getMessage());
}
// check for time validity
if (inTime.compareTo(time) < 0 || outTime.compareTo(inTime) <= 0) {
logger.warn("Caption with invalid time encountered. Skipping...");
continue;
}
time = outTime;
// get text captions
String[] captionLines = createCaptionLines(captionParts[2]);
if (captionLines == null) {
throw new CaptionConverterException("Caption does not contain any caption text: " + captionString);
}
// create caption object and add to caption collection
Caption caption = new CaptionImpl(inTime, outTime, captionLines);
collection.add(caption);
}
return collection;
}
/**
* {@inheritDoc} Since srt does not store information about language, language parameter is ignored.
*/
@Override
public void exportCaption(OutputStream outputStream, List<Caption> captions, String language) throws IOException {
if (language != null) {
logger.debug("SubRip format does not include language information. Ignoring language attribute.");
}
// initialize stream writer
OutputStreamWriter osw = new OutputStreamWriter(outputStream, "UTF-8");
BufferedWriter bw = new BufferedWriter(osw);
// initialize counter
int counter = 1;
for (Caption caption : captions) {
String captionString = String.format("%2$d%1$s%3$s --> %4$s%1$s%5$s%1$s%1$s", LINE_ENDING, counter,
TimeUtil.exportToSrt(caption.getStartTime()), TimeUtil.exportToSrt(caption.getStopTime()),
createCaptionText(caption.getCaption()));
bw.append(captionString);
counter++;
}
bw.flush();
bw.close();
osw.close();
}
/**
* Helper function that creates caption text.
*
* @param captionLines
* array containing caption lines
* @return string representation of caption text
*/
private String createCaptionText(String[] captionLines) {
StringBuilder builder = new StringBuilder(captionLines[0]);
for (int i = 1; i < captionLines.length; i++) {
builder.append(LINE_ENDING);
builder.append(captionLines[i]);
}
return builder.toString();
}
/**
* Helper function that splits text into lines and remove any style annotation
*
* @param captionText
* @return array of caption's text lines
*/
private String[] createCaptionLines(String captionText) {
String[] captionLines = captionText.split("\n");
if (captionLines.length == 0) {
return null;
}
for (int i = 0; i < captionLines.length; i++) {
captionLines[i] = captionLines[i].replaceAll("(<\\s*.\\s*>)|(</\\s*.\\s*>)", "").trim();
}
return captionLines;
}
/**
* {@inheritDoc} Returns empty list since srt format does not store any information about language.
*
* @see org.opencastproject.caption.api.CaptionConverter#getLanguageList(java.io.InputStream)
*/
@Override
public String[] getLanguageList(InputStream input) throws CaptionConverterException {
return new String[0];
}
/**
* {@inheritDoc}
*
* @see org.opencastproject.caption.api.CaptionConverter#getExtension()
*/
@Override
public String getExtension() {
return EXTENSION;
}
}