From 96b0336b2cbaa2166964757c089957bf4f1a420b Mon Sep 17 00:00:00 2001 From: Nathan Mascitelli Date: Sun, 10 Feb 2019 18:01:00 -0500 Subject: Update Timeline regex Regex now looks for the new types of short and long timestamps. --- .../main/java/de/danoeh/antennapod/core/util/Converter.java | 12 ++++++------ .../de/danoeh/antennapod/core/util/playback/Timeline.java | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'core/src') diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/Converter.java b/core/src/main/java/de/danoeh/antennapod/core/util/Converter.java index 6966667bf..1f9418c98 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/Converter.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/Converter.java @@ -76,11 +76,11 @@ public final class Converter { /** Converts milliseconds to a string containing hours and minutes */ public static String getDurationStringShort(int duration) { - int h = duration / HOURS_MIL; - int rest = duration - h * HOURS_MIL; - int m = rest / MINUTES_MIL; + int minutes = duration / MINUTES_MIL; + int rest = duration - minutes * MINUTES_MIL; + int seconds = rest / SECONDS_MIL; - return String.format(Locale.getDefault(), "%02d:%02d", h, m); + return String.format(Locale.getDefault(), "%02d:%02d", minutes, seconds); } /** Converts long duration string (HH:MM:SS) to milliseconds. */ @@ -100,8 +100,8 @@ public final class Converter { if (parts.length != 2) { return 0; } - return Integer.parseInt(parts[0]) * 3600 * 1000 + - Integer.parseInt(parts[1]) * 1000 * 60; + return Integer.parseInt(parts[0]) * 60 * 1000 + + Integer.parseInt(parts[1]) * 1000; } /** Converts milliseconds to a localized string containing hours and minutes */ 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 34cfe6d05..22349b029 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 @@ -68,7 +68,7 @@ public class Timeline { private static final Pattern TIMECODE_LINK_REGEX = Pattern.compile("antennapod://timecode/((\\d+))"); private static final String TIMECODE_LINK = "%s"; - private static final Pattern TIMECODE_REGEX = Pattern.compile("\\b(?:(?:(([0-9][0-9])):))?(([0-9][0-9])):(([0-9][0-9]))\\b"); + private static final Pattern TIMECODE_REGEX = Pattern.compile("\\b(?:(?:([01]?\\d|2[0-3]):)?([0-5]?\\d):)?([0-5]?\\d)\\b"); private static final Pattern LINE_BREAK_REGEX = Pattern.compile("
"); -- cgit v1.2.3 From d0f617880cda8bacfc70610d5ef04a6c8805a74b Mon Sep 17 00:00:00 2001 From: Nathan Mascitelli Date: Tue, 12 Feb 2019 17:32:58 -0500 Subject: Converter handles HH:MM and MM:SS --- .../de/danoeh/antennapod/core/util/Converter.java | 29 ++++++++++++++-------- 1 file changed, 18 insertions(+), 11 deletions(-) (limited to 'core/src') diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/Converter.java b/core/src/main/java/de/danoeh/antennapod/core/util/Converter.java index 1f9418c98..6ecca941a 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/Converter.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/Converter.java @@ -74,13 +74,14 @@ public final class Converter { return String.format(Locale.getDefault(), "%02d:%02d:%02d", h, m, s); } - /** Converts milliseconds to a string containing hours and minutes */ - public static String getDurationStringShort(int duration) { - int minutes = duration / MINUTES_MIL; - int rest = duration - minutes * MINUTES_MIL; - int seconds = rest / SECONDS_MIL; - - return String.format(Locale.getDefault(), "%02d:%02d", minutes, seconds); + /** Converts milliseconds to a string containing hours and minutes or minutes and seconds*/ + public static String getDurationStringShort(int duration, boolean durationIsInHours) { + int firstPartBase = durationIsInHours ? HOURS_MIL : MINUTES_MIL; + int firstPart = duration / firstPartBase; + int leftoverFromFirstPart = duration - firstPart * firstPartBase; + int secondPart = leftoverFromFirstPart / (durationIsInHours ? MINUTES_MIL : SECONDS_MIL); + + return String.format(Locale.getDefault(), "%02d:%02d", firstPart, secondPart); } /** Converts long duration string (HH:MM:SS) to milliseconds. */ @@ -94,14 +95,20 @@ public final class Converter { Integer.parseInt(parts[2]) * 1000; } - /** Converts short duration string (HH:MM) to milliseconds. */ - public static int durationStringShortToMs(String input) { + /** + * Converts short duration string (XX:YY) to milliseconds. If durationIsInHours is true then the + * format is HH:MM, otherwise it's MM:SS. + * */ + public static int durationStringShortToMs(String input, boolean durationIsInHours) { String[] parts = input.split(":"); if (parts.length != 2) { return 0; } - return Integer.parseInt(parts[0]) * 60 * 1000 + - Integer.parseInt(parts[1]) * 1000; + + int modifier = durationIsInHours ? 60 : 1; + + return Integer.parseInt(parts[0]) * 60 * 1000 * modifier+ + Integer.parseInt(parts[1]) * 1000 * modifier; } /** Converts milliseconds to a localized string containing hours and minutes */ -- cgit v1.2.3 From 39b9df50642dae9ac4129f22721093a6ce43148b Mon Sep 17 00:00:00 2001 From: Nathan Mascitelli Date: Tue, 12 Feb 2019 19:43:57 -0500 Subject: Timecode parsing logic now handles two short formats We now handle both HH:MM and MM:SS when paring timecodes. We will move in reverse order (assuming that the timecodes will increase over the course of the document) and parse short codes as HH:MM. When we get a result that does not fit into the duration we will change to parse as MM:SS and use that for the rest of the document. --- .../antennapod/core/util/playback/Timeline.java | 98 ++++++++++++++++------ 1 file changed, 74 insertions(+), 24 deletions(-) (limited to 'core/src') 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 22349b029..5b58596f7 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 @@ -7,6 +7,7 @@ import android.support.annotation.ColorInt; import android.support.annotation.NonNull; import android.text.TextUtils; import android.util.Log; +import android.util.Pair; import android.util.TypedValue; import org.jsoup.Jsoup; @@ -14,6 +15,7 @@ import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements; +import java.util.ArrayList; import java.util.Locale; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -127,35 +129,12 @@ public class Timeline { // apply timecode links if (addTimecodes) { - Elements elementsWithTimeCodes = document.body().getElementsMatchingOwnText(TIMECODE_REGEX); - Log.d(TAG, "Recognized " + elementsWithTimeCodes.size() + " timecodes"); - for (Element element : elementsWithTimeCodes) { - Matcher matcherLong = TIMECODE_REGEX.matcher(element.html()); - StringBuffer buffer = new StringBuffer(); - while (matcherLong.find()) { - String h = matcherLong.group(1); - String group = matcherLong.group(0); - int time = (h != null) ? Converter.durationStringLongToMs(group) : - Converter.durationStringShortToMs(group); - - String rep; - if (playable == null || playable.getDuration() > time) { - rep = String.format(Locale.getDefault(), TIMECODE_LINK, time, group); - } else { - rep = group; - } - matcherLong.appendReplacement(buffer, rep); - } - matcherLong.appendTail(buffer); - - element.html(buffer.toString()); - } + addTimecodes(document, playable); } return document.toString(); } - /** * Returns true if the given link is a timecode link. */ @@ -186,4 +165,75 @@ public class Timeline { public void setShownotesProvider(@NonNull ShownotesProvider shownotesProvider) { this.shownotesProvider = shownotesProvider; } + + private void addTimecodes(Document document, final Playable playable) { + 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 + 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))); + } + + // 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); + + String rep = group; + if (playable == null) { + rep = createTimeLink(time, group); + } else { + int duration = playable.getDuration(); + + 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); + useHourFormat = false; + } + } + } + + replacements.add(0, rep); + } + + // Now that we have all the replacements, replace. + StringBuffer buffer = new StringBuffer(); + int index = 0; + matcherLong.reset(); + while (matcherLong.find()) { + matcherLong.appendReplacement(buffer, replacements.get(index)); + index++; + } + + matcherLong.appendTail(buffer); + element.html(buffer.toString()); + } + } + + private String createTimeLink(int time, String group) { + return String.format(Locale.getDefault(), TIMECODE_LINK, time, group); + } } -- cgit v1.2.3 From c49e98b5462c9511dffe250a94b17be637884c49 Mon Sep 17 00:00:00 2001 From: Nathan Mascitelli Date: Tue, 12 Feb 2019 20:53:17 -0500 Subject: Handle more then 23 hours --- .../src/main/java/de/danoeh/antennapod/core/util/playback/Timeline.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'core/src') 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 5b58596f7..34f00fe79 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 @@ -70,7 +70,7 @@ public class Timeline { private static final Pattern TIMECODE_LINK_REGEX = Pattern.compile("antennapod://timecode/((\\d+))"); private static final String TIMECODE_LINK = "%s"; - private static final Pattern TIMECODE_REGEX = Pattern.compile("\\b(?:(?:([01]?\\d|2[0-3]):)?([0-5]?\\d):)?([0-5]?\\d)\\b"); + private static final Pattern TIMECODE_REGEX = Pattern.compile("\\b(?:(?:(\\d*):)?([0-5]?\\d):)?([0-5]?\\d)\\b"); private static final Pattern LINE_BREAK_REGEX = Pattern.compile("
"); -- cgit v1.2.3 From e94e4bc3d03d2e6d5122700fd3161bfa63dc4371 Mon Sep 17 00:00:00 2001 From: Nathan Mascitelli Date: Wed, 13 Feb 2019 21:06:19 -0500 Subject: 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. --- .../antennapod/core/util/playback/Timeline.java | 96 ++++++++++------------ 1 file changed, 45 insertions(+), 51 deletions(-) (limited to 'core/src') 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))); - } - // 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); - - String rep = group; - if (playable == null) { - rep = createTimeLink(time, group); - } else { - int duration = playable.getDuration(); - - 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 (playableDuration != Integer.MAX_VALUE) { + + // 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()) { + + // We only want short timecodes right now. + if (matcherForElement.group(1) == null) { + int time = Converter.durationStringShortToMs(matcherForElement.group(0), true); + + // 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); - } } -- cgit v1.2.3 From 6f69b4b1403f2ca4a7fd1125d145bf13252c3732 Mon Sep 17 00:00:00 2001 From: Nathan Mascitelli Date: Sat, 2 Mar 2019 08:47:52 -0500 Subject: Adjust regext to ignore X:Y timecodes --- .../src/main/java/de/danoeh/antennapod/core/util/playback/Timeline.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'core/src') 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 057de06dd..7b9a49fa8 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 @@ -70,7 +70,7 @@ public class Timeline { private static final Pattern TIMECODE_LINK_REGEX = Pattern.compile("antennapod://timecode/((\\d+))"); private static final String TIMECODE_LINK = "%s"; - private static final Pattern TIMECODE_REGEX = Pattern.compile("\\b(?:(?:(\\d*):)?([0-5]?\\d):)?([0-5]?\\d)\\b"); + private static final Pattern TIMECODE_REGEX = Pattern.compile("\\b(?:(?:(\\d*):)?([0-5]?\\d):)?([0-5][0-9]?\\d)\\b"); private static final Pattern LINE_BREAK_REGEX = Pattern.compile("
"); -- cgit v1.2.3 From 7e3ccd97da53108b8c5cec06cc0ae42454cdf42e Mon Sep 17 00:00:00 2001 From: Nathan Mascitelli Date: Sat, 2 Mar 2019 12:12:26 -0500 Subject: Fix regex --- .../src/main/java/de/danoeh/antennapod/core/util/playback/Timeline.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'core/src') 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 7b9a49fa8..07dd5b3a7 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 @@ -70,7 +70,7 @@ public class Timeline { private static final Pattern TIMECODE_LINK_REGEX = Pattern.compile("antennapod://timecode/((\\d+))"); private static final String TIMECODE_LINK = "%s"; - private static final Pattern TIMECODE_REGEX = Pattern.compile("\\b(?:(?:(\\d*):)?([0-5]?\\d):)?([0-5][0-9]?\\d)\\b"); + private static final Pattern TIMECODE_REGEX = Pattern.compile("\\b(?:(?:(\\d*):)?([0-5]?\\d))?:([0-5]\\d)\\b"); private static final Pattern LINE_BREAK_REGEX = Pattern.compile("
"); -- cgit v1.2.3 From 1d0e701525a33c638822a59241d99b96e026649a Mon Sep 17 00:00:00 2001 From: Nathan Mascitelli Date: Sun, 3 Mar 2019 13:36:28 -0500 Subject: Another atempt at fixing the regex --- .../src/main/java/de/danoeh/antennapod/core/util/playback/Timeline.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'core/src') 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 07dd5b3a7..56550bb06 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 @@ -70,7 +70,7 @@ public class Timeline { private static final Pattern TIMECODE_LINK_REGEX = Pattern.compile("antennapod://timecode/((\\d+))"); private static final String TIMECODE_LINK = "%s"; - private static final Pattern TIMECODE_REGEX = Pattern.compile("\\b(?:(?:(\\d*):)?([0-5]?\\d))?:([0-5]\\d)\\b"); + private static final Pattern TIMECODE_REGEX = Pattern.compile("\\b((\\d+):)?(\\d+):(\\d{2})\\b"); private static final Pattern LINE_BREAK_REGEX = Pattern.compile("
"); -- cgit v1.2.3