Use a single format for short timecodes
It is unlikely that multiple formats for short timecodes would be used in one document. Therefor we will parse all the short timecodes to see if they are all less then the duration as HH:MM. If they are we will use that, otherwise we will parse them as MM:SS.
This commit is contained in:
parent
c49e98b546
commit
e94e4bc3d0
|
@ -110,12 +110,14 @@ public class TimelineTest extends InstrumentationTestCase {
|
|||
}
|
||||
|
||||
public void testProcessShownotesAddTimecodeMultipleShortFormatNoChapters() throws Exception {
|
||||
|
||||
// One of these timecodes fits as HH:MM and one does not so both should be parsed as MM:SS.
|
||||
final String[] timeStrings = new String[]{ "10:12", "2:12" };
|
||||
|
||||
Playable p = newTestPlayable(null, "<p> Some test text with a timecode " + timeStrings[0] + " here. Hey look another one " + timeStrings[1] + " here!</p>", 3 * 60 * 60 * 1000);
|
||||
Timeline t = new Timeline(context, p);
|
||||
String res = t.processShownotes(true);
|
||||
checkLinkCorrect(res, new long[]{ 10 * 60 * 1000 + 12 * 1000, 2 * 60 * 60 * 1000 + 12 * 60 * 1000 }, timeStrings);
|
||||
checkLinkCorrect(res, new long[]{ 10 * 60 * 1000 + 12 * 1000, 2 * 60 * 1000 + 12 * 1000 }, timeStrings);
|
||||
}
|
||||
|
||||
public void testProcessShownotesAddTimecodeParentheses() throws Exception {
|
||||
|
|
|
@ -170,70 +170,64 @@ public class Timeline {
|
|||
Elements elementsWithTimeCodes = document.body().getElementsMatchingOwnText(TIMECODE_REGEX);
|
||||
Log.d(TAG, "Recognized " + elementsWithTimeCodes.size() + " timecodes");
|
||||
|
||||
// Assuming the timecodes are going to increase through the document loop through the
|
||||
// elements backwards so we can determine when/if we need to shift from HH:MM to MM:SS
|
||||
if (elementsWithTimeCodes.size() == 0) {
|
||||
// No elements with timecodes
|
||||
return;
|
||||
}
|
||||
|
||||
int playableDuration = playable == null ? Integer.MAX_VALUE : playable.getDuration();
|
||||
boolean useHourFormat = true;
|
||||
for (int i = elementsWithTimeCodes.size() - 1; i >= 0 ; i--) {
|
||||
Element element = elementsWithTimeCodes.get(i);
|
||||
Matcher matcherLong = TIMECODE_REGEX.matcher(element.html());
|
||||
|
||||
// Get all matches and store in reverse order
|
||||
ArrayList<Pair<Boolean, String>> matches = new ArrayList<>();
|
||||
while (matcherLong.find()) {
|
||||
matches.add(0, new Pair<>(matcherLong.group(1) != null, matcherLong.group(0)));
|
||||
}
|
||||
if (playableDuration != Integer.MAX_VALUE) {
|
||||
|
||||
// Now loop through the reversed matches and get the replacements. Store them in
|
||||
// non-reversed order.
|
||||
ArrayList<String> replacements = new ArrayList<>();
|
||||
for (Pair<Boolean, String> matchPair : matches) {
|
||||
boolean isLongFormat = matchPair.first;
|
||||
String group = matchPair.second;
|
||||
int time = isLongFormat
|
||||
? Converter.durationStringLongToMs(group)
|
||||
: Converter.durationStringShortToMs(group, useHourFormat);
|
||||
// We need to decide if we are going to treat short timecodes as HH:MM or MM:SS. To do
|
||||
// so we will parse all the short timecodes and see if they fit in the duration. If one
|
||||
// does not we will use MM:SS, otherwise all will be parsed as HH:MM.
|
||||
for (Element element : elementsWithTimeCodes) {
|
||||
Matcher matcherForElement = TIMECODE_REGEX.matcher(element.html());
|
||||
while (matcherForElement.find()) {
|
||||
|
||||
String rep = group;
|
||||
if (playable == null) {
|
||||
rep = createTimeLink(time, group);
|
||||
} else {
|
||||
int duration = playable.getDuration();
|
||||
// We only want short timecodes right now.
|
||||
if (matcherForElement.group(1) == null) {
|
||||
int time = Converter.durationStringShortToMs(matcherForElement.group(0), true);
|
||||
|
||||
if (duration > time) {
|
||||
rep = createTimeLink(time, group);
|
||||
} else if (!isLongFormat && useHourFormat) {
|
||||
|
||||
// The duration calculated in hours is too long and the timecode format is
|
||||
// short. So try and see if it will work when treated as minutes.
|
||||
time = Converter.durationStringShortToMs(group, false);
|
||||
|
||||
if (duration > time) {
|
||||
// We have found the treating a short timecode as minutes works, do that
|
||||
// from now on.
|
||||
rep = createTimeLink(time, group);
|
||||
// If the parsed timecode is greater then the duration then we know we need to
|
||||
// use the minute format so we are done.
|
||||
if (time > playableDuration) {
|
||||
useHourFormat = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
replacements.add(0, rep);
|
||||
if (!useHourFormat) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now that we have all the replacements, replace.
|
||||
for (Element element : elementsWithTimeCodes) {
|
||||
|
||||
Matcher matcherForElement = TIMECODE_REGEX.matcher(element.html());
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
int index = 0;
|
||||
matcherLong.reset();
|
||||
while (matcherLong.find()) {
|
||||
matcherLong.appendReplacement(buffer, replacements.get(index));
|
||||
index++;
|
||||
|
||||
while (matcherForElement.find()) {
|
||||
String group = matcherForElement.group(0);
|
||||
|
||||
int time = matcherForElement.group(1) != null
|
||||
? Converter.durationStringLongToMs(group)
|
||||
: Converter.durationStringShortToMs(group, useHourFormat);
|
||||
|
||||
String replacementText = group;
|
||||
if (time < playableDuration) {
|
||||
replacementText = String.format(Locale.getDefault(), TIMECODE_LINK, time, group);
|
||||
}
|
||||
|
||||
matcherForElement.appendReplacement(buffer, replacementText);
|
||||
}
|
||||
|
||||
matcherLong.appendTail(buffer);
|
||||
matcherForElement.appendTail(buffer);
|
||||
element.html(buffer.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private String createTimeLink(int time, String group) {
|
||||
return String.format(Locale.getDefault(), TIMECODE_LINK, time, group);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue