Skip to content

Commit 4586067

Browse files
AudricVTheta-Dev
authored andcommitted
Add utility method to parse textual durations using TimeAgoParser's patterns
This is required to parse duration of YouTube's reelItemRenderers, returned only inside accessibility data. Co-authored-by: ThetaDev <t.testboy@gmail.com>
1 parent d4bfe79 commit 4586067

1 file changed

Lines changed: 51 additions & 2 deletions

File tree

extractor/src/main/java/org/schabi/newpipe/extractor/localization/TimeAgoParser.java

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,21 @@
77
import java.time.OffsetDateTime;
88
import java.time.ZoneOffset;
99
import java.time.temporal.ChronoUnit;
10+
import java.util.ArrayList;
11+
import java.util.List;
1012
import java.util.Map;
1113
import java.util.regex.Pattern;
14+
import java.util.regex.Matcher;
15+
import java.util.regex.MatchResult;
1216

1317
/**
14-
* A helper class that is meant to be used by services that need to parse upload dates in the
15-
* format '2 days ago' or similar.
18+
* A helper class that is meant to be used by services that need to parse durations such as
19+
* {@code 23 seconds} and/or upload dates in the format {@code 2 days ago} or similar.
1620
*/
1721
public class TimeAgoParser {
22+
23+
private static final Pattern DURATION_PATTERN = Pattern.compile("(?:(\\d+) )?([A-z]+)");
24+
1825
private final PatternsHolder patternsHolder;
1926
private final OffsetDateTime now;
2027

@@ -60,6 +67,48 @@ public DateWrapper parse(final String textualDate) throws ParsingException {
6067
return getResultFor(parseTimeAgoAmount(textualDate), parseChronoUnit(textualDate));
6168
}
6269

70+
/**
71+
* Parses a textual duration into a duration computer number.
72+
*
73+
* @param textualDuration the textual duration to parse
74+
* @return the textual duration parsed, as a primitive {@code long}
75+
* @throws ParsingException if the textual duration could not be parsed
76+
*/
77+
public long parseDuration(final String textualDuration) throws ParsingException {
78+
// We can't use Matcher.results, as it is only available on Android 14 and above
79+
final Matcher matcher = DURATION_PATTERN.matcher(textualDuration);
80+
final List<MatchResult> results = new ArrayList<>();
81+
while (matcher.find()) {
82+
results.add(matcher.toMatchResult());
83+
}
84+
85+
return results.stream()
86+
.map(match -> {
87+
final String digits = match.group(1);
88+
final String word = match.group(2);
89+
90+
int amount;
91+
try {
92+
amount = Integer.parseInt(digits);
93+
} catch (final NumberFormatException ignored) {
94+
amount = 1;
95+
}
96+
97+
final ChronoUnit unit;
98+
try {
99+
unit = parseChronoUnit(word);
100+
} catch (final ParsingException ignored) {
101+
return 0L;
102+
}
103+
104+
return amount * unit.getDuration().getSeconds();
105+
})
106+
.filter(n -> n > 0)
107+
.reduce(Long::sum)
108+
.orElseThrow(() -> new ParsingException(
109+
"Could not parse duration \"" + textualDuration + "\""));
110+
}
111+
63112
private int parseTimeAgoAmount(final String textualDate) {
64113
try {
65114
return Integer.parseInt(textualDate.replaceAll("\\D+", ""));

0 commit comments

Comments
 (0)