Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,65 +1,78 @@
package org.schabi.newpipe.extractor.localization;

import org.schabi.newpipe.extractor.exceptions.ParsingException;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.Serializable;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.time.format.DateTimeParseException;

/**
* A wrapper class that provides a field to describe if the date/time is precise or just an
* approximation.
*/
public class DateWrapper implements Serializable {
@Nonnull
private final OffsetDateTime offsetDateTime;
private final Instant instant;
private final boolean isApproximation;

/**
* @deprecated Use {@link #DateWrapper(OffsetDateTime)} instead.
*/
@Deprecated
public DateWrapper(@Nonnull final Calendar calendar) {
//noinspection deprecation
this(calendar, false);
}

/**
* @deprecated Use {@link #DateWrapper(OffsetDateTime, boolean)} instead.
*/
@Deprecated
public DateWrapper(@Nonnull final Calendar calendar, final boolean isApproximation) {
this(OffsetDateTime.ofInstant(calendar.toInstant(), ZoneOffset.UTC), isApproximation);
}

public DateWrapper(@Nonnull final OffsetDateTime offsetDateTime) {
this(offsetDateTime, false);
}

public DateWrapper(@Nonnull final OffsetDateTime offsetDateTime,
final boolean isApproximation) {
this.offsetDateTime = offsetDateTime.withOffsetSameInstant(ZoneOffset.UTC);
this(offsetDateTime.toInstant(), isApproximation);
}

public DateWrapper(@Nonnull final Instant instant) {
this(instant, false);
}

public DateWrapper(@Nonnull final Instant instant, final boolean isApproximation) {
this.instant = instant;
this.isApproximation = isApproximation;
}

public DateWrapper(@Nonnull final LocalDateTime dateTime, final boolean isApproximation) {
this(dateTime.atZone(ZoneId.systemDefault()).toInstant(), isApproximation);
}

/**
* @return the wrapped date/time as a {@link Calendar}.
* @deprecated use {@link #offsetDateTime()} instead.
* @return the wrapped {@link Instant}
*/
@Deprecated
@Nonnull
public Calendar date() {
return GregorianCalendar.from(offsetDateTime.toZonedDateTime());
public Instant getInstant() {
return instant;
}

/**
* @return the wrapped date/time.
* @return the wrapped {@link Instant} as an {@link OffsetDateTime} set to UTC.
*/
@Nonnull
public OffsetDateTime offsetDateTime() {
return offsetDateTime;
return instant.atOffset(ZoneOffset.UTC);
}

/**
* @return the wrapped {@link Instant} as a {@link LocalDateTime} in the current time zone.
*/
@Nonnull
public LocalDateTime getLocalDateTime() {
return getLocalDateTime(ZoneId.systemDefault());
}

/**
* @return the wrapped {@link Instant} as a {@link LocalDateTime} in the given time zone.
*/
@Nonnull
public LocalDateTime getLocalDateTime(@Nonnull final ZoneId zoneId) {
return LocalDateTime.ofInstant(instant, zoneId);
}

/**
Expand All @@ -73,8 +86,42 @@ public boolean isApproximation() {
@Override
public String toString() {
return "DateWrapper{"
+ "offsetDateTime=" + offsetDateTime
+ "instant=" + instant
+ ", isApproximation=" + isApproximation
+ '}';
}

/**
* Parses a date string that matches the ISO-8601 {@link OffsetDateTime} pattern, e.g.
* "2011-12-03T10:15:30+01:00".
*
* @param date The date string
* @return a non-approximate {@link DateWrapper}, or null if the string is null
* @throws ParsingException if the string does not match the expected format
*/
@Nullable
public static DateWrapper fromOffsetDateTime(final String date) throws ParsingException {
try {
return date != null ? new DateWrapper(OffsetDateTime.parse(date)) : null;
} catch (final DateTimeParseException e) {
throw new ParsingException("Could not parse date: \"" + date + "\"", e);
}
}

/**
* Parses a date string that matches the ISO-8601 {@link Instant} pattern, e.g.
* "2011-12-03T10:15:30Z".
*
* @param date The date string
* @return a non-approximate {@link DateWrapper}, or null if the string is null
* @throws ParsingException if the string does not match the expected format
*/
@Nullable
public static DateWrapper fromInstant(final String date) throws ParsingException {
try {
return date != null ? new DateWrapper(Instant.parse(date)) : null;
} catch (final DateTimeParseException e) {
throw new ParsingException("Could not parse date: \"" + date + "\"", e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@
import org.schabi.newpipe.extractor.timeago.PatternsHolder;
import org.schabi.newpipe.extractor.utils.Parser;

import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.Map;
import java.util.regex.Pattern;
Expand All @@ -16,20 +15,7 @@
*/
public class TimeAgoParser {
private final PatternsHolder patternsHolder;
private final OffsetDateTime now;

/**
* Creates a helper to parse upload dates in the format '2 days ago'.
* <p>
* Instantiate a new {@link TimeAgoParser} every time you extract a new batch of items.
* </p>
*
* @param patternsHolder An object that holds the "time ago" patterns, special cases, and the
* language word separator.
*/
public TimeAgoParser(final PatternsHolder patternsHolder) {
this(patternsHolder, OffsetDateTime.now(ZoneOffset.UTC));
}
private final LocalDateTime now;

/**
* Creates a helper to parse upload dates in the format '2 days ago'.
Expand All @@ -41,7 +27,7 @@ public TimeAgoParser(final PatternsHolder patternsHolder) {
* language word separator.
* @param now The current time
*/
public TimeAgoParser(final PatternsHolder patternsHolder, final OffsetDateTime now) {
public TimeAgoParser(final PatternsHolder patternsHolder, final LocalDateTime now) {
this.patternsHolder = patternsHolder;
this.now = now;
}
Expand Down Expand Up @@ -118,34 +104,13 @@ private boolean textualDateMatches(final String textualDate, final String agoPhr
}

private DateWrapper getResultFor(final int timeAgoAmount, final ChronoUnit chronoUnit) {
OffsetDateTime offsetDateTime = now;
boolean isApproximation = false;

switch (chronoUnit) {
case SECONDS:
case MINUTES:
case HOURS:
offsetDateTime = offsetDateTime.minus(timeAgoAmount, chronoUnit);
break;

case DAYS:
case WEEKS:
case MONTHS:
offsetDateTime = offsetDateTime.minus(timeAgoAmount, chronoUnit);
isApproximation = true;
break;

case YEARS:
final var localDateTime = chronoUnit == ChronoUnit.YEARS
// minusDays is needed to prevent `PrettyTime` from showing '12 months ago'.
offsetDateTime = offsetDateTime.minusYears(timeAgoAmount).minusDays(1);
isApproximation = true;
break;
}

if (isApproximation) {
offsetDateTime = offsetDateTime.truncatedTo(ChronoUnit.HOURS);
}

return new DateWrapper(offsetDateTime, isApproximation);
? now.minusYears(timeAgoAmount).minusDays(1)
: now.minus(timeAgoAmount, chronoUnit);
final boolean isApproximate = chronoUnit.isDateBased();
final var resolvedDateTime =
isApproximate ? localDateTime.truncatedTo(ChronoUnit.DAYS) : localDateTime;
return new DateWrapper(resolvedDateTime, isApproximate);
Comment thread
Isira-Seneviratne marked this conversation as resolved.
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import org.schabi.newpipe.extractor.timeago.PatternsHolder;
import org.schabi.newpipe.extractor.timeago.PatternsManager;

import java.time.OffsetDateTime;
import java.time.LocalDateTime;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
Expand All @@ -20,25 +20,13 @@ private static PatternsHolder getPatternsFor(@Nonnull final Localization localiz

@Nullable
public static TimeAgoParser getTimeAgoParserFor(@Nonnull final Localization localization) {
final PatternsHolder holder = getPatternsFor(localization);

if (holder == null) {
return null;
}

return new TimeAgoParser(holder);
return getTimeAgoParserFor(localization, LocalDateTime.now());
}

@Nullable
public static TimeAgoParser getTimeAgoParserFor(
@Nonnull final Localization localization,
@Nonnull final OffsetDateTime now) {
public static TimeAgoParser getTimeAgoParserFor(@Nonnull final Localization localization,
@Nonnull final LocalDateTime now) {
final PatternsHolder holder = getPatternsFor(localization);

if (holder == null) {
return null;
}

return new TimeAgoParser(holder, now);
return holder == null ? null : new TimeAgoParser(holder, now);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ public static DateWrapper parseDate(final String textDate) throws ParsingExcepti
try {
final ZonedDateTime zonedDateTime = ZonedDateTime.parse(textDate,
DateTimeFormatter.ofPattern("dd MMM yyyy HH:mm:ss zzz", Locale.ENGLISH));
return new DateWrapper(zonedDateTime.toOffsetDateTime(), false);
return new DateWrapper(zonedDateTime.toInstant());
} catch (final DateTimeException e) {
throw new ParsingException("Could not parse date '" + textDate + "'", e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,12 @@
import org.schabi.newpipe.extractor.Image.ResolutionLevel;
import org.schabi.newpipe.extractor.downloader.Downloader;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;
import org.schabi.newpipe.extractor.localization.Localization;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.IOException;
import java.time.OffsetDateTime;
import java.time.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
Expand All @@ -33,15 +30,6 @@ public final class MediaCCCParsingHelper {

private MediaCCCParsingHelper() { }

public static OffsetDateTime parseDateFrom(final String textualUploadDate)
throws ParsingException {
try {
return OffsetDateTime.parse(textualUploadDate);
} catch (final DateTimeParseException e) {
throw new ParsingException("Could not parse date: \"" + textualUploadDate + "\"", e);
}
}

/**
* Check whether an id is a live stream id
* @param id the {@code id} to check
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,10 @@ public InfoItemsPage<StreamInfoItem> getInitialPage() throws IOException, Extrac

// Streams in the recent kiosk are not ordered by the release date.
// Sort them to have the latest stream at the beginning of the list.
final Comparator<StreamInfoItem> comparator = Comparator
.comparing(StreamInfoItem::getUploadDate, Comparator
.nullsLast(Comparator.comparing(DateWrapper::offsetDateTime)))
final var comparator = Comparator.comparing(StreamInfoItem::getUploadDate,
Comparator.nullsLast(Comparator.comparing(DateWrapper::getInstant)))
.reversed();
final StreamInfoItemsCollector collector = new StreamInfoItemsCollector(getServiceId(),
comparator);
final var collector = new StreamInfoItemsCollector(getServiceId(), comparator);

events.stream()
.filter(JsonObject.class::isInstance)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,6 @@ public String getTextualUploadDate() throws ParsingException {
public DateWrapper getUploadDate() throws ParsingException {
final ZonedDateTime zonedDateTime = ZonedDateTime.parse(event.getString("date"),
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSzzzz"));
return new DateWrapper(zonedDateTime.toOffsetDateTime(), false);
return new DateWrapper(zonedDateTime.toInstant());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import static org.schabi.newpipe.extractor.services.media_ccc.extractors.MediaCCCParsingHelper.getImageListFromLogoImageUrl;
import static org.schabi.newpipe.extractor.services.media_ccc.extractors.MediaCCCParsingHelper.getThumbnailsFromStreamItem;
import static org.schabi.newpipe.extractor.services.media_ccc.extractors.MediaCCCParsingHelper.parseDateFrom;
import static org.schabi.newpipe.extractor.stream.AudioStream.UNKNOWN_BITRATE;
import static org.schabi.newpipe.extractor.stream.Stream.ID_UNKNOWN;

Expand Down Expand Up @@ -37,6 +36,7 @@
import java.util.Locale;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

public class MediaCCCStreamExtractor extends StreamExtractor {
private JsonObject data;
Expand All @@ -46,16 +46,16 @@ public MediaCCCStreamExtractor(final StreamingService service, final LinkHandler
super(service, linkHandler);
}

@Nonnull
@Nullable
@Override
public String getTextualUploadDate() {
return data.getString("release_date");
}

@Nonnull
@Nullable
@Override
public DateWrapper getUploadDate() throws ParsingException {
return new DateWrapper(parseDateFrom(getTextualUploadDate()));
return DateWrapper.fromOffsetDateTime(getTextualUploadDate());
}

@Nonnull
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import org.schabi.newpipe.extractor.Image;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.localization.DateWrapper;
import org.schabi.newpipe.extractor.services.media_ccc.extractors.MediaCCCParsingHelper;
import org.schabi.newpipe.extractor.stream.StreamInfoItemExtractor;
import org.schabi.newpipe.extractor.stream.StreamType;

Expand Down Expand Up @@ -65,11 +64,8 @@ public String getTextualUploadDate() {
@Nullable
@Override
public DateWrapper getUploadDate() throws ParsingException {
final String date = getTextualUploadDate();
if (date == null) {
return null; // event is in the future...
}
return new DateWrapper(MediaCCCParsingHelper.parseDateFrom(date));
// if null, event is in the future...
return DateWrapper.fromOffsetDateTime(getTextualUploadDate());
}

@Override
Expand Down
Loading