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>
This commit is contained in:
AudricV 2023-07-14 19:55:01 +02:00 committed by Stypox
parent d4bfe791ee
commit 4586067934
No known key found for this signature in database
GPG Key ID: 4BDF1B40A49FDD23
1 changed files with 51 additions and 2 deletions

View File

@ -7,14 +7,21 @@ import org.schabi.newpipe.extractor.utils.Parser;
import java.time.OffsetDateTime; import java.time.OffsetDateTime;
import java.time.ZoneOffset; import java.time.ZoneOffset;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.regex.Matcher;
import java.util.regex.MatchResult;
/** /**
* A helper class that is meant to be used by services that need to parse upload dates in the * A helper class that is meant to be used by services that need to parse durations such as
* format '2 days ago' or similar. * {@code 23 seconds} and/or upload dates in the format {@code 2 days ago} or similar.
*/ */
public class TimeAgoParser { public class TimeAgoParser {
private static final Pattern DURATION_PATTERN = Pattern.compile("(?:(\\d+) )?([A-z]+)");
private final PatternsHolder patternsHolder; private final PatternsHolder patternsHolder;
private final OffsetDateTime now; private final OffsetDateTime now;
@ -60,6 +67,48 @@ public class TimeAgoParser {
return getResultFor(parseTimeAgoAmount(textualDate), parseChronoUnit(textualDate)); return getResultFor(parseTimeAgoAmount(textualDate), parseChronoUnit(textualDate));
} }
/**
* Parses a textual duration into a duration computer number.
*
* @param textualDuration the textual duration to parse
* @return the textual duration parsed, as a primitive {@code long}
* @throws ParsingException if the textual duration could not be parsed
*/
public long parseDuration(final String textualDuration) throws ParsingException {
// We can't use Matcher.results, as it is only available on Android 14 and above
final Matcher matcher = DURATION_PATTERN.matcher(textualDuration);
final List<MatchResult> results = new ArrayList<>();
while (matcher.find()) {
results.add(matcher.toMatchResult());
}
return results.stream()
.map(match -> {
final String digits = match.group(1);
final String word = match.group(2);
int amount;
try {
amount = Integer.parseInt(digits);
} catch (final NumberFormatException ignored) {
amount = 1;
}
final ChronoUnit unit;
try {
unit = parseChronoUnit(word);
} catch (final ParsingException ignored) {
return 0L;
}
return amount * unit.getDuration().getSeconds();
})
.filter(n -> n > 0)
.reduce(Long::sum)
.orElseThrow(() -> new ParsingException(
"Could not parse duration \"" + textualDuration + "\""));
}
private int parseTimeAgoAmount(final String textualDate) { private int parseTimeAgoAmount(final String textualDate) {
try { try {
return Integer.parseInt(textualDate.replaceAll("\\D+", "")); return Integer.parseInt(textualDate.replaceAll("\\D+", ""));