diff --git a/app/src/androidTest/java/de/test/antennapod/util/playback/TimelineTest.java b/app/src/androidTest/java/de/test/antennapod/util/playback/TimelineTest.java index 157773595..e6b11a4b0 100644 --- a/app/src/androidTest/java/de/test/antennapod/util/playback/TimelineTest.java +++ b/app/src/androidTest/java/de/test/antennapod/util/playback/TimelineTest.java @@ -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, "

Some test text with a timecode " + timeStrings[0] + " here. Hey look another one " + timeStrings[1] + " here!

", 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 { diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/playback/Timeline.java b/core/src/main/java/de/danoeh/antennapod/core/util/playback/Timeline.java index 34f00fe79..057de06dd 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/playback/Timeline.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/playback/Timeline.java @@ -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> 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 replacements = new ArrayList<>(); - for (Pair 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); - } }