diff --git a/README.md b/README.md index 36e2f7b52..11e616f39 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,8 @@ If you're using Gradle, you could add NewPipe Extractor as a dependency with the 1. Add `maven { url 'https://jitpack.io' }` to the `repositories` in your `build.gradle`. 2. Add `implementation 'com.github.TeamNewPipe:NewPipeExtractor:v0.20.1'`the `dependencies` in your `build.gradle`. Replace `v0.20.1` with the latest release. +**Note:** To use NewPipe Extractor in projects with a `minSdkVersion` below 26, [API desugaring](https://developer.android.com/studio/write/java8-support#library-desugaring) is required. + ### Testing changes To test changes quickly you can build the library locally. A good approach would be to add something like the following to your `settings.gradle`: diff --git a/build.gradle b/build.gradle index 4701f58e7..070ed43ff 100644 --- a/build.gradle +++ b/build.gradle @@ -2,8 +2,8 @@ allprojects { apply plugin: 'java-library' apply plugin: 'maven' - sourceCompatibility = 1.7 - targetCompatibility = 1.7 + sourceCompatibility = 1.8 + targetCompatibility = 1.8 version 'v0.20.2' group 'com.github.TeamNewPipe' diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/localization/DateWrapper.java b/extractor/src/main/java/org/schabi/newpipe/extractor/localization/DateWrapper.java index 433287852..0390ee12e 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/localization/DateWrapper.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/localization/DateWrapper.java @@ -3,30 +3,61 @@ package org.schabi.newpipe.extractor.localization; import edu.umd.cs.findbugs.annotations.NonNull; import java.io.Serializable; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; import java.util.Calendar; +import java.util.GregorianCalendar; /** - * A wrapper class that provides a field to describe if the date is precise or just an approximation. + * 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 Calendar date; + @NonNull private final OffsetDateTime offsetDateTime; private final boolean isApproximation; - public DateWrapper(@NonNull Calendar date) { - this(date, false); + /** + * @deprecated Use {@link #DateWrapper(OffsetDateTime)} instead. + */ + @Deprecated + public DateWrapper(@NonNull Calendar calendar) { + this(calendar, false); } - public DateWrapper(@NonNull Calendar date, boolean isApproximation) { - this.date = date; + /** + * @deprecated Use {@link #DateWrapper(OffsetDateTime, boolean)} instead. + */ + @Deprecated + public DateWrapper(@NonNull Calendar calendar, boolean isApproximation) { + offsetDateTime = OffsetDateTime.ofInstant(calendar.toInstant(), ZoneOffset.UTC); + this.isApproximation = isApproximation; + } + + public DateWrapper(@NonNull OffsetDateTime offsetDateTime) { + this(offsetDateTime, false); + } + + public DateWrapper(@NonNull OffsetDateTime offsetDateTime, boolean isApproximation) { + this.offsetDateTime = offsetDateTime.withOffsetSameInstant(ZoneOffset.UTC); this.isApproximation = isApproximation; } /** - * @return the wrapped date. + * @return the wrapped date/time as a {@link Calendar}. + * + * @deprecated use {@link #offsetDateTime()} instead. */ + @Deprecated @NonNull public Calendar date() { - return date; + return GregorianCalendar.from(offsetDateTime.toZonedDateTime()); + } + + /** + * @return the wrapped date/time. + */ + @NonNull + public OffsetDateTime offsetDateTime() { + return offsetDateTime; } /** diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/localization/TimeAgoParser.java b/extractor/src/main/java/org/schabi/newpipe/extractor/localization/TimeAgoParser.java index fe20135f8..dd74f9aae 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/localization/TimeAgoParser.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/localization/TimeAgoParser.java @@ -2,10 +2,11 @@ package org.schabi.newpipe.extractor.localization; import org.schabi.newpipe.extractor.exceptions.ParsingException; import org.schabi.newpipe.extractor.timeago.PatternsHolder; -import org.schabi.newpipe.extractor.timeago.TimeAgoUnit; import org.schabi.newpipe.extractor.utils.Parser; -import java.util.Calendar; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.time.temporal.ChronoUnit; import java.util.Collection; import java.util.Map; import java.util.regex.Pattern; @@ -16,7 +17,7 @@ import java.util.regex.Pattern; */ public class TimeAgoParser { private final PatternsHolder patternsHolder; - private final Calendar consistentNow; + private final OffsetDateTime now; /** * Creates a helper to parse upload dates in the format '2 days ago'. @@ -28,7 +29,7 @@ public class TimeAgoParser { */ public TimeAgoParser(PatternsHolder patternsHolder) { this.patternsHolder = patternsHolder; - consistentNow = Calendar.getInstance(); + now = OffsetDateTime.now(ZoneOffset.UTC); } /** @@ -42,14 +43,14 @@ public class TimeAgoParser { * @throws ParsingException if the time unit could not be recognized */ public DateWrapper parse(String textualDate) throws ParsingException { - for (Map.Entry> caseUnitEntry : patternsHolder.specialCases().entrySet()) { - final TimeAgoUnit timeAgoUnit = caseUnitEntry.getKey(); + for (Map.Entry> caseUnitEntry : patternsHolder.specialCases().entrySet()) { + final ChronoUnit chronoUnit = caseUnitEntry.getKey(); for (Map.Entry caseMapToAmountEntry : caseUnitEntry.getValue().entrySet()) { final String caseText = caseMapToAmountEntry.getKey(); final Integer caseAmount = caseMapToAmountEntry.getValue(); if (textualDateMatches(textualDate, caseText)) { - return getResultFor(caseAmount, timeAgoUnit); + return getResultFor(caseAmount, chronoUnit); } } } @@ -63,8 +64,8 @@ public class TimeAgoParser { timeAgoAmount = 1; } - final TimeAgoUnit timeAgoUnit = parseTimeAgoUnit(textualDate); - return getResultFor(timeAgoAmount, timeAgoUnit); + final ChronoUnit chronoUnit = parseChronoUnit(textualDate); + return getResultFor(timeAgoAmount, chronoUnit); } private int parseTimeAgoAmount(String textualDate) throws NumberFormatException { @@ -72,13 +73,13 @@ public class TimeAgoParser { return Integer.parseInt(timeValueStr); } - private TimeAgoUnit parseTimeAgoUnit(String textualDate) throws ParsingException { - for (Map.Entry> entry : patternsHolder.asMap().entrySet()) { - final TimeAgoUnit timeAgoUnit = entry.getKey(); + private ChronoUnit parseChronoUnit(String textualDate) throws ParsingException { + for (Map.Entry> entry : patternsHolder.asMap().entrySet()) { + final ChronoUnit chronoUnit = entry.getKey(); for (String agoPhrase : entry.getValue()) { if (textualDateMatches(textualDate, agoPhrase)) { - return timeAgoUnit; + return chronoUnit; } } } @@ -112,65 +113,35 @@ public class TimeAgoParser { } } - private DateWrapper getResultFor(int timeAgoAmount, TimeAgoUnit timeAgoUnit) { - final Calendar calendarTime = getNow(); + private DateWrapper getResultFor(int timeAgoAmount, ChronoUnit chronoUnit) { + OffsetDateTime offsetDateTime = now; boolean isApproximation = false; - switch (timeAgoUnit) { + switch (chronoUnit) { case SECONDS: - calendarTime.add(Calendar.SECOND, -timeAgoAmount); - break; - case MINUTES: - calendarTime.add(Calendar.MINUTE, -timeAgoAmount); - break; - case HOURS: - calendarTime.add(Calendar.HOUR_OF_DAY, -timeAgoAmount); + offsetDateTime = offsetDateTime.minus(timeAgoAmount, chronoUnit); break; case DAYS: - calendarTime.add(Calendar.DAY_OF_MONTH, -timeAgoAmount); - isApproximation = true; - break; - case WEEKS: - calendarTime.add(Calendar.WEEK_OF_YEAR, -timeAgoAmount); - isApproximation = true; - break; - case MONTHS: - calendarTime.add(Calendar.MONTH, -timeAgoAmount); + offsetDateTime = offsetDateTime.minus(timeAgoAmount, chronoUnit); isApproximation = true; break; case YEARS: - calendarTime.add(Calendar.YEAR, -timeAgoAmount); - // Prevent `PrettyTime` from showing '12 months ago'. - calendarTime.add(Calendar.DAY_OF_MONTH, -1); + // minusDays is needed to prevent `PrettyTime` from showing '12 months ago'. + offsetDateTime = offsetDateTime.minusYears(timeAgoAmount).minusDays(1); isApproximation = true; break; } if (isApproximation) { - markApproximatedTime(calendarTime); + offsetDateTime = offsetDateTime.truncatedTo(ChronoUnit.HOURS); } - return new DateWrapper(calendarTime, isApproximation); - } - - private Calendar getNow() { - return (Calendar) consistentNow.clone(); - } - - /** - * Marks the time as approximated by setting minutes, seconds and milliseconds to 0. - * - * @param calendarTime Time to be marked as approximated - */ - private void markApproximatedTime(Calendar calendarTime) { - calendarTime.set(Calendar.MINUTE, 0); - calendarTime.set(Calendar.SECOND, 0); - calendarTime.set(Calendar.MILLISECOND, 0); + return new DateWrapper(offsetDateTime, isApproximation); } } diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCParsingHelper.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCParsingHelper.java index 14ca5c52c..b6879fcdf 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCParsingHelper.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCParsingHelper.java @@ -2,28 +2,17 @@ package org.schabi.newpipe.extractor.services.media_ccc.extractors; import org.schabi.newpipe.extractor.exceptions.ParsingException; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Calendar; -import java.util.Date; -import java.util.TimeZone; +import java.time.OffsetDateTime; +import java.time.format.DateTimeParseException; public final class MediaCCCParsingHelper { private MediaCCCParsingHelper() { } - public static Calendar parseDateFrom(final String textualUploadDate) throws ParsingException { - final Date date; + public static OffsetDateTime parseDateFrom(final String textualUploadDate) throws ParsingException { try { - final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); - sdf.setTimeZone(TimeZone.getTimeZone("GMT")); - date = sdf.parse(textualUploadDate); - } catch (ParseException e) { + return OffsetDateTime.parse(textualUploadDate); + } catch (DateTimeParseException e) { throw new ParsingException("Could not parse date: \"" + textualUploadDate + "\"", e); } - - final Calendar uploadDate = Calendar.getInstance(); - uploadDate.setTime(date); - return uploadDate; } - } diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/PeertubeParsingHelper.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/PeertubeParsingHelper.java index 5c6ceac42..42d183f42 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/PeertubeParsingHelper.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/PeertubeParsingHelper.java @@ -2,7 +2,6 @@ package org.schabi.newpipe.extractor.services.peertube; import com.grack.nanojson.JsonArray; import com.grack.nanojson.JsonObject; - import org.schabi.newpipe.extractor.InfoItemsCollector; import org.schabi.newpipe.extractor.Page; import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException; @@ -12,11 +11,10 @@ import org.schabi.newpipe.extractor.utils.JsonUtils; import org.schabi.newpipe.extractor.utils.Parser; import org.schabi.newpipe.extractor.utils.Utils; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Calendar; -import java.util.Date; -import java.util.TimeZone; +import java.time.Instant; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.time.format.DateTimeParseException; public class PeertubeParsingHelper { public static final String START_KEY = "start"; @@ -34,19 +32,12 @@ public class PeertubeParsingHelper { } } - public static Calendar parseDateFrom(final String textualUploadDate) throws ParsingException { - final Date date; + public static OffsetDateTime parseDateFrom(final String textualUploadDate) throws ParsingException { try { - final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.S'Z'"); - sdf.setTimeZone(TimeZone.getTimeZone("GMT")); - date = sdf.parse(textualUploadDate); - } catch (ParseException e) { + return OffsetDateTime.ofInstant(Instant.parse(textualUploadDate), ZoneOffset.UTC); + } catch (DateTimeParseException e) { throw new ParsingException("Could not parse date: \"" + textualUploadDate + "\"", e); } - - final Calendar uploadDate = Calendar.getInstance(); - uploadDate.setTime(date); - return uploadDate; } public static Page getNextPage(final String prevPageUrl, final long total) { diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/soundcloud/SoundcloudParsingHelper.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/soundcloud/SoundcloudParsingHelper.java index 0a3c400a0..566acd39b 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/soundcloud/SoundcloudParsingHelper.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/soundcloud/SoundcloudParsingHelper.java @@ -21,16 +21,18 @@ import org.schabi.newpipe.extractor.services.soundcloud.extractors.SoundcloudStr import org.schabi.newpipe.extractor.stream.StreamInfoItemsCollector; import org.schabi.newpipe.extractor.utils.Parser; import org.schabi.newpipe.extractor.utils.Parser.RegexException; -import org.schabi.newpipe.extractor.utils.Utils; import javax.annotation.Nonnull; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.net.URLEncoder; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.*; +import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; import static java.util.Collections.singletonList; import static org.schabi.newpipe.extractor.ServiceList.SoundCloud; @@ -95,23 +97,16 @@ public class SoundcloudParsingHelper { } } - public static Calendar parseDateFrom(String textualUploadDate) throws ParsingException { - Date date; + public static OffsetDateTime parseDateFrom(String textualUploadDate) throws ParsingException { try { - SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); - sdf.setTimeZone(TimeZone.getTimeZone("GMT")); - date = sdf.parse(textualUploadDate); - } catch (ParseException e1) { + return OffsetDateTime.parse(textualUploadDate); + } catch (DateTimeParseException e1) { try { - date = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss +0000").parse(textualUploadDate); - } catch (ParseException e2) { + return OffsetDateTime.parse(textualUploadDate, DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss +0000")); + } catch (DateTimeParseException e2) { throw new ParsingException("Could not parse date: \"" + textualUploadDate + "\"" + ", " + e1.getMessage(), e2); } } - - final Calendar uploadDate = Calendar.getInstance(); - uploadDate.setTime(date); - return uploadDate; } /** diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeParsingHelper.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeParsingHelper.java index a8ca2a03a..3fb279b8e 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeParsingHelper.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeParsingHelper.java @@ -5,7 +5,6 @@ import com.grack.nanojson.JsonObject; import com.grack.nanojson.JsonParser; import com.grack.nanojson.JsonParserException; import com.grack.nanojson.JsonWriter; - import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.schabi.newpipe.extractor.downloader.Response; @@ -22,13 +21,18 @@ import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; import java.net.URL; import java.net.URLDecoder; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.*; +import java.time.OffsetDateTime; +import java.time.format.DateTimeParseException; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import static org.schabi.newpipe.extractor.NewPipe.getDownloader; import static org.schabi.newpipe.extractor.utils.JsonUtils.EMPTY_STRING; -import static org.schabi.newpipe.extractor.utils.Utils.*; +import static org.schabi.newpipe.extractor.utils.Utils.HTTP; +import static org.schabi.newpipe.extractor.utils.Utils.HTTPS; +import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty; /* * Created by Christian Schabesberger on 02.03.16. @@ -176,19 +180,12 @@ public class YoutubeParsingHelper { } } - public static Calendar parseDateFrom(String textualUploadDate) throws ParsingException { - final Date date; + public static OffsetDateTime parseDateFrom(String textualUploadDate) throws ParsingException { try { - final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); - sdf.setTimeZone(TimeZone.getTimeZone("GMT")); - date = sdf.parse(textualUploadDate); - } catch (ParseException e) { + return OffsetDateTime.parse(textualUploadDate); + } catch (DateTimeParseException e) { throw new ParsingException("Could not parse date: \"" + textualUploadDate + "\"", e); } - - final Calendar uploadDate = Calendar.getInstance(); - uploadDate.setTime(date); - return uploadDate; } public static JsonObject getInitialData(String html) throws ParsingException { diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeFeedInfoItemExtractor.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeFeedInfoItemExtractor.java index aadc80223..cea385189 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeFeedInfoItemExtractor.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeFeedInfoItemExtractor.java @@ -7,11 +7,9 @@ import org.schabi.newpipe.extractor.stream.StreamInfoItemExtractor; import org.schabi.newpipe.extractor.stream.StreamType; import javax.annotation.Nullable; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Calendar; -import java.util.Date; -import java.util.TimeZone; +import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; public class YoutubeFeedInfoItemExtractor implements StreamInfoItemExtractor { private final Element entryElement; @@ -62,19 +60,11 @@ public class YoutubeFeedInfoItemExtractor implements StreamInfoItemExtractor { @Nullable @Override public DateWrapper getUploadDate() throws ParsingException { - final Date date; try { - final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss+00:00"); - dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); - date = dateFormat.parse(getTextualUploadDate()); - } catch (ParseException e) { + return new DateWrapper(OffsetDateTime.parse(getTextualUploadDate(), DateTimeFormatter.ISO_OFFSET_DATE_TIME)); + } catch (DateTimeParseException e) { throw new ParsingException("Could not parse date (\"" + getTextualUploadDate() + "\")", e); } - - final Calendar calendar = Calendar.getInstance(); - calendar.setTime(date); - - return new DateWrapper(calendar); } @Override diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeStreamExtractor.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeStreamExtractor.java index 708613f0c..d86c63d9c 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeStreamExtractor.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeStreamExtractor.java @@ -43,11 +43,11 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.io.IOException; import java.io.UnsupportedEncodingException; -import java.text.SimpleDateFormat; +import java.time.LocalDate; +import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; import java.util.ArrayList; -import java.util.Calendar; import java.util.Collections; -import java.util.Date; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; @@ -157,23 +157,24 @@ public class YoutubeStreamExtractor extends StreamExtractor { try { // Premiered 20 hours ago TimeAgoParser timeAgoParser = TimeAgoPatternsManager.getTimeAgoParserFor(Localization.fromLocalizationCode("en")); - Calendar parsedTime = timeAgoParser.parse(time).date(); - return new SimpleDateFormat("yyyy-MM-dd").format(parsedTime.getTime()); + OffsetDateTime parsedTime = timeAgoParser.parse(time).offsetDateTime(); + return DateTimeFormatter.ISO_LOCAL_DATE.format(parsedTime); } catch (Exception ignored) { } try { // Premiered Feb 21, 2020 - Date d = new SimpleDateFormat("MMM dd, YYYY", Locale.ENGLISH).parse(time); - return new SimpleDateFormat("yyyy-MM-dd").format(d.getTime()); + LocalDate localDate = LocalDate.parse(time, + DateTimeFormatter.ofPattern("MMM dd, YYYY", Locale.ENGLISH)); + return DateTimeFormatter.ISO_LOCAL_DATE.format(localDate); } catch (Exception ignored) { } } try { // TODO: this parses English formatted dates only, we need a better approach to parse the textual date - Date d = new SimpleDateFormat("dd MMM yyyy", Locale.ENGLISH).parse( - getTextFromObject(getVideoPrimaryInfoRenderer().getObject("dateText"))); - return new SimpleDateFormat("yyyy-MM-dd").format(d); + LocalDate localDate = LocalDate.parse(getTextFromObject(getVideoPrimaryInfoRenderer().getObject("dateText")), + DateTimeFormatter.ofPattern("dd MMM yyyy", Locale.ENGLISH)); + return DateTimeFormatter.ISO_LOCAL_DATE.format(localDate); } catch (Exception ignored) { } throw new ParsingException("Could not get upload date"); diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeStreamInfoItemExtractor.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeStreamInfoItemExtractor.java index 0757208ee..ae784f206 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeStreamInfoItemExtractor.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeStreamInfoItemExtractor.java @@ -12,11 +12,14 @@ import org.schabi.newpipe.extractor.stream.StreamType; import org.schabi.newpipe.extractor.utils.Utils; import javax.annotation.Nullable; -import java.text.SimpleDateFormat; -import java.util.Calendar; -import java.util.Date; +import java.time.Instant; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; -import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.*; +import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.fixThumbnailUrl; +import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getTextFromObject; +import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getUrlFromNavigationEndpoint; import static org.schabi.newpipe.extractor.utils.JsonUtils.EMPTY_STRING; import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty; @@ -165,8 +168,7 @@ public class YoutubeStreamInfoItemExtractor implements StreamInfoItemExtractor { } if (isPremiere()) { - final Date date = getDateFromPremiere().getTime(); - return new SimpleDateFormat("yyyy-MM-dd HH:mm").format(date); + return DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm").format(getDateFromPremiere()); } final String publishedTimeText = getTextFromObject(videoInfo.getObject("publishedTimeText")); @@ -250,15 +252,13 @@ public class YoutubeStreamInfoItemExtractor implements StreamInfoItemExtractor { return videoInfo.has("upcomingEventData"); } - private Calendar getDateFromPremiere() throws ParsingException { + private OffsetDateTime getDateFromPremiere() throws ParsingException { final JsonObject upcomingEventData = videoInfo.getObject("upcomingEventData"); final String startTime = upcomingEventData.getString("startTime"); try { - final long startTimeTimestamp = Long.parseLong(startTime); - final Calendar calendar = Calendar.getInstance(); - calendar.setTime(new Date(startTimeTimestamp * 1000L)); - return calendar; + return OffsetDateTime.ofInstant(Instant.ofEpochSecond(Long.parseLong(startTime)), + ZoneOffset.UTC); } catch (Exception e) { throw new ParsingException("Could not parse date from premiere: \"" + startTime + "\""); } diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/DefaultStreamExtractorTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/DefaultStreamExtractorTest.java index a70b38a8a..19c767ae8 100644 --- a/extractor/src/test/java/org/schabi/newpipe/extractor/services/DefaultStreamExtractorTest.java +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/DefaultStreamExtractorTest.java @@ -12,14 +12,12 @@ import org.schabi.newpipe.extractor.stream.StreamType; import org.schabi.newpipe.extractor.stream.SubtitlesStream; import org.schabi.newpipe.extractor.stream.VideoStream; -import java.text.SimpleDateFormat; -import java.util.Calendar; +import javax.annotation.Nullable; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import java.util.Collections; import java.util.List; import java.util.Locale; -import java.util.TimeZone; - -import javax.annotation.Nullable; import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.MatcherAssert.assertThat; @@ -171,13 +169,11 @@ public abstract class DefaultStreamExtractorTest extends DefaultExtractorTest months; private final Collection years; - private final Map> specialCases = new LinkedHashMap<>(); + private final Map> specialCases = new LinkedHashMap<>(); protected PatternsHolder(String wordSeparator, Collection seconds, Collection minutes, Collection hours, Collection days, @@ -69,30 +70,25 @@ public abstract class PatternsHolder { return years; } - public Map> specialCases() { + public Map> specialCases() { return specialCases; } - protected void putSpecialCase(TimeAgoUnit unit, String caseText, int caseAmount) { - Map item = specialCases.get(unit); - - if (item == null) { - item = new LinkedHashMap<>(); - specialCases.put(unit, item); - } + protected void putSpecialCase(ChronoUnit unit, String caseText, int caseAmount) { + Map item = specialCases.computeIfAbsent(unit, k -> new LinkedHashMap<>()); item.put(caseText, caseAmount); } - public Map> asMap() { - final Map> returnMap = new LinkedHashMap<>(); - returnMap.put(TimeAgoUnit.SECONDS, seconds()); - returnMap.put(TimeAgoUnit.MINUTES, minutes()); - returnMap.put(TimeAgoUnit.HOURS, hours()); - returnMap.put(TimeAgoUnit.DAYS, days()); - returnMap.put(TimeAgoUnit.WEEKS, weeks()); - returnMap.put(TimeAgoUnit.MONTHS, months()); - returnMap.put(TimeAgoUnit.YEARS, years()); + public Map> asMap() { + final Map> returnMap = new LinkedHashMap<>(); + returnMap.put(ChronoUnit.SECONDS, seconds()); + returnMap.put(ChronoUnit.MINUTES, minutes()); + returnMap.put(ChronoUnit.HOURS, hours()); + returnMap.put(ChronoUnit.DAYS, days()); + returnMap.put(ChronoUnit.WEEKS, weeks()); + returnMap.put(ChronoUnit.MONTHS, months()); + returnMap.put(ChronoUnit.YEARS, years()); return returnMap; } diff --git a/timeago-parser/src/main/java/org/schabi/newpipe/extractor/timeago/TimeAgoUnit.java b/timeago-parser/src/main/java/org/schabi/newpipe/extractor/timeago/TimeAgoUnit.java deleted file mode 100644 index 16e05c243..000000000 --- a/timeago-parser/src/main/java/org/schabi/newpipe/extractor/timeago/TimeAgoUnit.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.schabi.newpipe.extractor.timeago; - -public enum TimeAgoUnit { - SECONDS, - MINUTES, - HOURS, - DAYS, - WEEKS, - MONTHS, - YEARS -} diff --git a/timeago-parser/src/main/java/org/schabi/newpipe/extractor/timeago/patterns/iw.java b/timeago-parser/src/main/java/org/schabi/newpipe/extractor/timeago/patterns/iw.java index a04bf74f3..6f89e025f 100644 --- a/timeago-parser/src/main/java/org/schabi/newpipe/extractor/timeago/patterns/iw.java +++ b/timeago-parser/src/main/java/org/schabi/newpipe/extractor/timeago/patterns/iw.java @@ -5,7 +5,8 @@ package org.schabi.newpipe.extractor.timeago.patterns; import org.schabi.newpipe.extractor.timeago.PatternsHolder; -import org.schabi.newpipe.extractor.timeago.TimeAgoUnit; + +import java.time.temporal.ChronoUnit; public class iw extends PatternsHolder { private static final String WORD_SEPARATOR = " "; @@ -26,10 +27,10 @@ public class iw extends PatternsHolder { private iw() { super(WORD_SEPARATOR, SECONDS, MINUTES, HOURS, DAYS, WEEKS, MONTHS, YEARS); - putSpecialCase(TimeAgoUnit.HOURS, "שעתיים", 2); - putSpecialCase(TimeAgoUnit.DAYS, "יומיים", 2); - putSpecialCase(TimeAgoUnit.WEEKS, "שבועיים", 2); - putSpecialCase(TimeAgoUnit.MONTHS, "חודשיים", 2); - putSpecialCase(TimeAgoUnit.YEARS, "שנתיים", 2); + putSpecialCase(ChronoUnit.HOURS, "שעתיים", 2); + putSpecialCase(ChronoUnit.DAYS, "יומיים", 2); + putSpecialCase(ChronoUnit.WEEKS, "שבועיים", 2); + putSpecialCase(ChronoUnit.MONTHS, "חודשיים", 2); + putSpecialCase(ChronoUnit.YEARS, "שנתיים", 2); } } \ No newline at end of file