Skip to content

Commit b56cc38

Browse files
Merge branch 'dev' into Remove-LocaleCompat
# Conflicts: # extractor/src/main/java/org/schabi/newpipe/extractor/localization/TimeAgoPatternsManager.java # extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeStreamExtractor.java # extractor/src/test/java/org/schabi/newpipe/extractor/localization/TimeAgoParserTest.java
2 parents 1f26212 + 3af7326 commit b56cc38

108 files changed

Lines changed: 4357 additions & 644 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ If you're using Gradle, you could add NewPipe Extractor as a dependency with the
2020
-dontwarn org.mozilla.javascript.tools.**
2121
```
2222

23-
**Note:** To use NewPipe Extractor in Android projects with a `minSdk` below 33, [core library desugaring](https://developer.android.com/studio/write/java8-support#library-desugaring) with the `desugar_jdk_libs_nio` artifact is required.
23+
> [!NOTE]
24+
> To use NewPipe Extractor in Android projects with a `minSdk` below 33, [core library desugaring](https://developer.android.com/studio/write/java8-support#library-desugaring) with the `desugar_jdk_libs_nio` artifact is required.
2425
2526
### Testing changes
2627

@@ -41,6 +42,8 @@ Another approach would be to use the local Maven repository, here's a gist of ho
4142
3. Run gradle's `ìnstall` task to deploy this library to your local repository (using the wrapper, present in the root of this project: `./gradlew install`)
4243
4. Change the dependency version used in your project to match the one you chose in step 2 (`implementation 'com.github.teamnewpipe:NewPipeExtractor:LOCAL_SNAPSHOT'`)
4344

45+
46+
> [!TIP]
4447
> Tip for Android Studio users: After you make changes and run the `install` task, use the menu option `File → "Sync with File System"` to refresh the library in your project.
4548
4649
## Supported sites

build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ allprojects {
2929
ext {
3030
nanojsonVersion = "e9d656ddb49a412a5a0a5d5ef20ca7ef09549996"
3131
jsr305Version = "3.0.2"
32-
junitVersion = "5.13.4"
33-
checkstyleVersion = "10.4"
32+
junitVersion = "5.14.0"
33+
checkstyleVersion = "10.26.1"
3434
}
3535
}
3636

extractor/build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ checkstyleTest {
2828

2929
ext {
3030
rhinoVersion = '1.8.0'
31-
protobufVersion = '4.32.0'
31+
protobufVersion = '4.32.1'
3232
}
3333

3434
dependencies {
@@ -51,7 +51,7 @@ dependencies {
5151
testImplementation 'org.junit.jupiter:junit-jupiter-params'
5252

5353
testImplementation "com.squareup.okhttp3:okhttp:4.12.0"
54-
testImplementation 'com.google.code.gson:gson:2.13.1'
54+
testImplementation 'com.google.code.gson:gson:2.13.2'
5555
}
5656

5757
protobuf {
Lines changed: 83 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,78 @@
11
package org.schabi.newpipe.extractor.localization;
22

3+
import org.schabi.newpipe.extractor.exceptions.ParsingException;
34

45
import javax.annotation.Nonnull;
6+
import javax.annotation.Nullable;
57
import java.io.Serializable;
8+
import java.time.Instant;
9+
import java.time.LocalDateTime;
610
import java.time.OffsetDateTime;
11+
import java.time.ZoneId;
712
import java.time.ZoneOffset;
8-
import java.util.Calendar;
9-
import java.util.GregorianCalendar;
13+
import java.time.format.DateTimeParseException;
1014

1115
/**
1216
* A wrapper class that provides a field to describe if the date/time is precise or just an
1317
* approximation.
1418
*/
1519
public class DateWrapper implements Serializable {
1620
@Nonnull
17-
private final OffsetDateTime offsetDateTime;
21+
private final Instant instant;
1822
private final boolean isApproximation;
1923

20-
/**
21-
* @deprecated Use {@link #DateWrapper(OffsetDateTime)} instead.
22-
*/
23-
@Deprecated
24-
public DateWrapper(@Nonnull final Calendar calendar) {
25-
//noinspection deprecation
26-
this(calendar, false);
27-
}
28-
29-
/**
30-
* @deprecated Use {@link #DateWrapper(OffsetDateTime, boolean)} instead.
31-
*/
32-
@Deprecated
33-
public DateWrapper(@Nonnull final Calendar calendar, final boolean isApproximation) {
34-
this(OffsetDateTime.ofInstant(calendar.toInstant(), ZoneOffset.UTC), isApproximation);
35-
}
36-
3724
public DateWrapper(@Nonnull final OffsetDateTime offsetDateTime) {
3825
this(offsetDateTime, false);
3926
}
4027

4128
public DateWrapper(@Nonnull final OffsetDateTime offsetDateTime,
4229
final boolean isApproximation) {
43-
this.offsetDateTime = offsetDateTime.withOffsetSameInstant(ZoneOffset.UTC);
30+
this(offsetDateTime.toInstant(), isApproximation);
31+
}
32+
33+
public DateWrapper(@Nonnull final Instant instant) {
34+
this(instant, false);
35+
}
36+
37+
public DateWrapper(@Nonnull final Instant instant, final boolean isApproximation) {
38+
this.instant = instant;
4439
this.isApproximation = isApproximation;
4540
}
4641

42+
public DateWrapper(@Nonnull final LocalDateTime dateTime, final boolean isApproximation) {
43+
this(dateTime.atZone(ZoneId.systemDefault()).toInstant(), isApproximation);
44+
}
45+
4746
/**
48-
* @return the wrapped date/time as a {@link Calendar}.
49-
* @deprecated use {@link #offsetDateTime()} instead.
47+
* @return the wrapped {@link Instant}
5048
*/
51-
@Deprecated
5249
@Nonnull
53-
public Calendar date() {
54-
return GregorianCalendar.from(offsetDateTime.toZonedDateTime());
50+
public Instant getInstant() {
51+
return instant;
5552
}
5653

5754
/**
58-
* @return the wrapped date/time.
55+
* @return the wrapped {@link Instant} as an {@link OffsetDateTime} set to UTC.
5956
*/
6057
@Nonnull
6158
public OffsetDateTime offsetDateTime() {
62-
return offsetDateTime;
59+
return instant.atOffset(ZoneOffset.UTC);
60+
}
61+
62+
/**
63+
* @return the wrapped {@link Instant} as a {@link LocalDateTime} in the current time zone.
64+
*/
65+
@Nonnull
66+
public LocalDateTime getLocalDateTime() {
67+
return getLocalDateTime(ZoneId.systemDefault());
68+
}
69+
70+
/**
71+
* @return the wrapped {@link Instant} as a {@link LocalDateTime} in the given time zone.
72+
*/
73+
@Nonnull
74+
public LocalDateTime getLocalDateTime(@Nonnull final ZoneId zoneId) {
75+
return LocalDateTime.ofInstant(instant, zoneId);
6376
}
6477

6578
/**
@@ -69,4 +82,46 @@ public OffsetDateTime offsetDateTime() {
6982
public boolean isApproximation() {
7083
return isApproximation;
7184
}
85+
86+
@Override
87+
public String toString() {
88+
return "DateWrapper{"
89+
+ "instant=" + instant
90+
+ ", isApproximation=" + isApproximation
91+
+ '}';
92+
}
93+
94+
/**
95+
* Parses a date string that matches the ISO-8601 {@link OffsetDateTime} pattern, e.g.
96+
* "2011-12-03T10:15:30+01:00".
97+
*
98+
* @param date The date string
99+
* @return a non-approximate {@link DateWrapper}, or null if the string is null
100+
* @throws ParsingException if the string does not match the expected format
101+
*/
102+
@Nullable
103+
public static DateWrapper fromOffsetDateTime(final String date) throws ParsingException {
104+
try {
105+
return date != null ? new DateWrapper(OffsetDateTime.parse(date)) : null;
106+
} catch (final DateTimeParseException e) {
107+
throw new ParsingException("Could not parse date: \"" + date + "\"", e);
108+
}
109+
}
110+
111+
/**
112+
* Parses a date string that matches the ISO-8601 {@link Instant} pattern, e.g.
113+
* "2011-12-03T10:15:30Z".
114+
*
115+
* @param date The date string
116+
* @return a non-approximate {@link DateWrapper}, or null if the string is null
117+
* @throws ParsingException if the string does not match the expected format
118+
*/
119+
@Nullable
120+
public static DateWrapper fromInstant(final String date) throws ParsingException {
121+
try {
122+
return date != null ? new DateWrapper(Instant.parse(date)) : null;
123+
} catch (final DateTimeParseException e) {
124+
throw new ParsingException("Could not parse date: \"" + date + "\"", e);
125+
}
126+
}
72127
}

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

Lines changed: 10 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@
44
import org.schabi.newpipe.extractor.timeago.PatternsHolder;
55
import org.schabi.newpipe.extractor.utils.Parser;
66

7-
import java.time.OffsetDateTime;
8-
import java.time.ZoneOffset;
7+
import java.time.LocalDateTime;
98
import java.time.temporal.ChronoUnit;
109
import java.util.Map;
1110
import java.util.regex.Pattern;
@@ -16,20 +15,7 @@
1615
*/
1716
public class TimeAgoParser {
1817
private final PatternsHolder patternsHolder;
19-
private final OffsetDateTime now;
20-
21-
/**
22-
* Creates a helper to parse upload dates in the format '2 days ago'.
23-
* <p>
24-
* Instantiate a new {@link TimeAgoParser} every time you extract a new batch of items.
25-
* </p>
26-
*
27-
* @param patternsHolder An object that holds the "time ago" patterns, special cases, and the
28-
* language word separator.
29-
*/
30-
public TimeAgoParser(final PatternsHolder patternsHolder) {
31-
this(patternsHolder, OffsetDateTime.now(ZoneOffset.UTC));
32-
}
18+
private final LocalDateTime now;
3319

3420
/**
3521
* Creates a helper to parse upload dates in the format '2 days ago'.
@@ -41,7 +27,7 @@ public TimeAgoParser(final PatternsHolder patternsHolder) {
4127
* language word separator.
4228
* @param now The current time
4329
*/
44-
public TimeAgoParser(final PatternsHolder patternsHolder, final OffsetDateTime now) {
30+
public TimeAgoParser(final PatternsHolder patternsHolder, final LocalDateTime now) {
4531
this.patternsHolder = patternsHolder;
4632
this.now = now;
4733
}
@@ -118,34 +104,13 @@ private boolean textualDateMatches(final String textualDate, final String agoPhr
118104
}
119105

120106
private DateWrapper getResultFor(final int timeAgoAmount, final ChronoUnit chronoUnit) {
121-
OffsetDateTime offsetDateTime = now;
122-
boolean isApproximation = false;
123-
124-
switch (chronoUnit) {
125-
case SECONDS:
126-
case MINUTES:
127-
case HOURS:
128-
offsetDateTime = offsetDateTime.minus(timeAgoAmount, chronoUnit);
129-
break;
130-
131-
case DAYS:
132-
case WEEKS:
133-
case MONTHS:
134-
offsetDateTime = offsetDateTime.minus(timeAgoAmount, chronoUnit);
135-
isApproximation = true;
136-
break;
137-
138-
case YEARS:
107+
final var localDateTime = chronoUnit == ChronoUnit.YEARS
139108
// minusDays is needed to prevent `PrettyTime` from showing '12 months ago'.
140-
offsetDateTime = offsetDateTime.minusYears(timeAgoAmount).minusDays(1);
141-
isApproximation = true;
142-
break;
143-
}
144-
145-
if (isApproximation) {
146-
offsetDateTime = offsetDateTime.truncatedTo(ChronoUnit.HOURS);
147-
}
148-
149-
return new DateWrapper(offsetDateTime, isApproximation);
109+
? now.minusYears(timeAgoAmount).minusDays(1)
110+
: now.minus(timeAgoAmount, chronoUnit);
111+
final boolean isApproximate = chronoUnit.isDateBased();
112+
final var resolvedDateTime =
113+
isApproximate ? localDateTime.truncatedTo(ChronoUnit.DAYS) : localDateTime;
114+
return new DateWrapper(resolvedDateTime, isApproximate);
150115
}
151116
}

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@
33
import org.schabi.newpipe.extractor.timeago.PatternMap;
44
import org.schabi.newpipe.extractor.timeago.PatternsHolder;
55

6+
import java.time.LocalDateTime;
7+
68
import javax.annotation.Nonnull;
79
import javax.annotation.Nullable;
8-
import java.time.OffsetDateTime;
910
import java.util.Locale;
1011

1112
public final class TimeAgoPatternsManager {
@@ -23,14 +24,13 @@ private static PatternsHolder getPatternsFor(@Nonnull final Locale locale) {
2324

2425
@Nullable
2526
public static TimeAgoParser getTimeAgoParserFor(@Nonnull final Locale locale) {
26-
final var holder = getPatternsFor(locale);
27-
return holder == null ? null : new TimeAgoParser(holder);
27+
return getTimeAgoParserFor(locale, LocalDateTime.now());
2828
}
2929

3030
@Nullable
3131
public static TimeAgoParser getTimeAgoParserFor(@Nonnull final Locale locale,
32-
@Nonnull final OffsetDateTime now) {
33-
final var holder = getPatternsFor(locale);
32+
@Nonnull final LocalDateTime now) {
33+
final PatternsHolder holder = getPatternsFor(locale);
3434
return holder == null ? null : new TimeAgoParser(holder, now);
3535
}
3636
}

extractor/src/main/java/org/schabi/newpipe/extractor/services/bandcamp/extractors/BandcampExtractorHelper.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ public static DateWrapper parseDate(final String textDate) throws ParsingExcepti
204204
try {
205205
final ZonedDateTime zonedDateTime = ZonedDateTime.parse(textDate,
206206
DateTimeFormatter.ofPattern("dd MMM yyyy HH:mm:ss zzz", Locale.ENGLISH));
207-
return new DateWrapper(zonedDateTime.toOffsetDateTime(), false);
207+
return new DateWrapper(zonedDateTime.toInstant());
208208
} catch (final DateTimeException e) {
209209
throw new ParsingException("Could not parse date '" + textDate + "'", e);
210210
}

extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCParsingHelper.java

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,11 @@
88
import org.schabi.newpipe.extractor.Image.ResolutionLevel;
99
import org.schabi.newpipe.extractor.downloader.Downloader;
1010
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
11-
import org.schabi.newpipe.extractor.exceptions.ParsingException;
1211
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;
1312

1413
import javax.annotation.Nonnull;
1514
import javax.annotation.Nullable;
1615
import java.io.IOException;
17-
import java.time.OffsetDateTime;
18-
import java.time.format.DateTimeParseException;
1916
import java.util.ArrayList;
2017
import java.util.Collections;
2118
import java.util.List;
@@ -33,15 +30,6 @@ public final class MediaCCCParsingHelper {
3330

3431
private MediaCCCParsingHelper() { }
3532

36-
public static OffsetDateTime parseDateFrom(final String textualUploadDate)
37-
throws ParsingException {
38-
try {
39-
return OffsetDateTime.parse(textualUploadDate);
40-
} catch (final DateTimeParseException e) {
41-
throw new ParsingException("Could not parse date: \"" + textualUploadDate + "\"", e);
42-
}
43-
}
44-
4533
/**
4634
* Check whether an id is a live stream id
4735
* @param id the {@code id} to check

extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCRecentKiosk.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,10 @@ public InfoItemsPage<StreamInfoItem> getInitialPage() throws IOException, Extrac
5252

5353
// Streams in the recent kiosk are not ordered by the release date.
5454
// Sort them to have the latest stream at the beginning of the list.
55-
final Comparator<StreamInfoItem> comparator = Comparator
56-
.comparing(StreamInfoItem::getUploadDate, Comparator
57-
.nullsLast(Comparator.comparing(DateWrapper::offsetDateTime)))
55+
final var comparator = Comparator.comparing(StreamInfoItem::getUploadDate,
56+
Comparator.nullsLast(Comparator.comparing(DateWrapper::getInstant)))
5857
.reversed();
59-
final StreamInfoItemsCollector collector = new StreamInfoItemsCollector(getServiceId(),
60-
comparator);
58+
final var collector = new StreamInfoItemsCollector(getServiceId(), comparator);
6159

6260
events.stream()
6361
.filter(JsonObject.class::isInstance)

extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCRecentKioskExtractor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,6 @@ public String getTextualUploadDate() throws ParsingException {
9292
public DateWrapper getUploadDate() throws ParsingException {
9393
final ZonedDateTime zonedDateTime = ZonedDateTime.parse(event.getString("date"),
9494
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSzzzz"));
95-
return new DateWrapper(zonedDateTime.toOffsetDateTime(), false);
95+
return new DateWrapper(zonedDateTime.toInstant());
9696
}
9797
}

0 commit comments

Comments
 (0)