/*
* This file is part of Popcorn Time.
*
* Popcorn Time is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Popcorn Time is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Popcorn Time. If not, see <http://www.gnu.org/licenses/>.
*/
package pct.droid.base.subs;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
/**
* This class represents the .SRT subtitle format
* <br><br>
* Copyright (c) 2012 J. David Requejo <br>
* j[dot]david[dot]requejo[at] Gmail
* <br><br>
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
* and associated documentation files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following conditions:
* <br><br>
* The above copyright notice and this permission notice shall be included in all copies
* or substantial portions of the Software.
* <br><br>
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
* FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* @author J. David Requejo
*/
public class FormatSRT extends TimedTextFileFormat {
public TimedTextObject parseFile(String fileName, String[] inputString) throws IOException {
TimedTextObject tto = new TimedTextObject();
Caption caption = new Caption();
int captionNumber = 1;
boolean allGood;
//the file name is saved
tto.fileName = fileName;
int lineCounter = 0;
int stringIndex = 0;
String line;
try {
line = getLine(inputString, stringIndex++);
while (line != null && stringIndex < inputString.length) {
line = line.trim();
lineCounter++;
//if its a blank line, ignore it, otherwise...
if (!line.isEmpty()) {
allGood = false;
//the first thing should be an increasing number
try {
int num = Integer.parseInt(line);
if (num != captionNumber)
throw new Exception();
else {
captionNumber++;
allGood = true;
}
} catch (Exception e) {
tto.warnings += captionNumber + " expected at line " + lineCounter;
tto.warnings += "\n skipping to next line\n\n";
}
if (allGood) {
//we go to next line, here the begin and end time should be found
try {
lineCounter++;
line = getLine(inputString, stringIndex++).trim();
String start = line.substring(0, 12);
String end = line.substring(line.length() - 12, line.length());
Time time = new Time("hh:mm:ss,ms", start);
caption.start = time;
time = new Time("hh:mm:ss,ms", end);
caption.end = time;
} catch (Exception e) {
tto.warnings += "incorrect time format at line " + lineCounter;
allGood = false;
}
}
if (allGood) {
//we go to next line where the caption text starts
lineCounter++;
line = getLine(inputString, stringIndex++).trim();
String text = "";
while (!line.isEmpty() && stringIndex < inputString.length) {
text += line + "<br />";
line = getLine(inputString, stringIndex++).trim();
lineCounter++;
}
caption.content = text;
int key = caption.start.mseconds;
//in case the key is already there, we increase it by a millisecond, since no duplicates are allowed
while (tto.captions.containsKey(key)) key++;
if (key != caption.start.mseconds)
tto.warnings += "caption with same start time found...\n\n";
//we add the caption.
tto.captions.put(key, caption);
}
//we go to next blank
while (!line.isEmpty() && stringIndex < inputString.length) {
line = getLine(inputString, stringIndex++).trim();
lineCounter++;
}
caption = new Caption();
}
if (stringIndex < inputString.length) {
line = getLine(inputString, stringIndex++);
}
}
} catch (NullPointerException e) {
tto.warnings += "unexpected end of file, maybe last caption is not complete.\n\n";
}
tto.built = true;
return tto;
}
public String[] toFile(TimedTextObject tto) {
//first we check if the TimedTextObject had been built, otherwise...
if (!tto.built)
return null;
//we will write the lines in an ArrayList,
int index = 0;
//the minimum size of the file is 4*number of captions, so we'll take some extra space.
ArrayList<String> file = new ArrayList<>(5 * tto.captions.size());
//we iterate over our captions collection, they are ordered since they come from a TreeMap
Collection<Caption> c = tto.captions.values();
Iterator<Caption> itr = c.iterator();
int captionNumber = 1;
while (itr.hasNext()) {
//new caption
Caption current = itr.next();
//number is written
file.add(index++, "" + captionNumber++);
//we check for offset value:
if (tto.offset != 0) {
current.start.mseconds += tto.offset;
current.end.mseconds += tto.offset;
}
//time is written
file.add(index++, current.start.getTime("hh:mm:ss,ms") + " --> " + current.end.getTime("hh:mm:ss,ms"));
//offset is undone
if (tto.offset != 0) {
current.start.mseconds -= tto.offset;
current.end.mseconds -= tto.offset;
}
//text is added
String[] lines = cleanTextForSRT(current);
int i = 0;
while (i < lines.length)
file.add(index++, "" + lines[i++]);
//we add the next blank line
file.add(index++, "");
}
return file.toArray(new String[file.size()]);
}
/* PRIVATE METHODS */
/**
* This method cleans caption.content of XML and parses line breaks.
*/
private String[] cleanTextForSRT(Caption current) {
String[] lines;
String text = current.content;
//add line breaks
lines = text.split("<br />");
//clean XML
for (int i = 0; i < lines.length; i++) {
//this will destroy all remaining XML tags
lines[i] = lines[i].replaceAll("<.*?>", "");
}
return lines;
}
}