From 5e7818cd84f04d6c84c8965b16d73c91eea011d8 Mon Sep 17 00:00:00 2001
From: David Asunmo <22662897+davidasunmo@users.noreply.github.com.>
Date: Thu, 22 May 2025 04:46:38 +0100
Subject: [PATCH 01/13] Fix typo
---
.../java/org/schabi/newpipe/extractor/utils/ImageSuffix.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/utils/ImageSuffix.java b/extractor/src/main/java/org/schabi/newpipe/extractor/utils/ImageSuffix.java
index 4d8a141917..7332c75c08 100644
--- a/extractor/src/main/java/org/schabi/newpipe/extractor/utils/ImageSuffix.java
+++ b/extractor/src/main/java/org/schabi/newpipe/extractor/utils/ImageSuffix.java
@@ -14,7 +14,7 @@
*
* This class is used to construct {@link org.schabi.newpipe.extractor.Image Image}
* instances from a single base URL/path, in order to get all or most image resolutions provided,
- * depending of the service and the resolutions provided.
+ * depending on the service and the resolutions provided.
*
*
*
From d9af459ecfff8802a0e6ec7061202123e36175d4 Mon Sep 17 00:00:00 2001
From: David Asunmo <22662897+davidasunmo@users.noreply.github.com.>
Date: Mon, 26 May 2025 04:39:10 +0100
Subject: [PATCH 02/13] Remove redundant override
---
.../services/soundcloud/SoundcloudStreamExtractorTest.java | 1 -
1 file changed, 1 deletion(-)
diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/soundcloud/SoundcloudStreamExtractorTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/soundcloud/SoundcloudStreamExtractorTest.java
index d33ea37443..d7fab32d1f 100644
--- a/extractor/src/test/java/org/schabi/newpipe/extractor/services/soundcloud/SoundcloudStreamExtractorTest.java
+++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/soundcloud/SoundcloudStreamExtractorTest.java
@@ -132,7 +132,6 @@ public void testRelatedItems() throws Exception {
@Override public long expectedDislikeCountAtLeast() { return -1; }
@Override public boolean expectedHasAudioStreams() { return false; }
@Override public boolean expectedHasVideoStreams() { return false; }
- @Override public boolean expectedHasRelatedItems() { return true; }
@Override public boolean expectedHasSubtitles() { return false; }
@Override public boolean expectedHasFrames() { return false; }
@Override public int expectedStreamSegmentsCount() { return 0; }
From 5fcd97104c5116d56a578688ddfb082d7c92405f Mon Sep 17 00:00:00 2001
From: David Asunmo <22662897+davidasunmo@users.noreply.github.com.>
Date: Wed, 4 Jun 2025 05:06:13 +0100
Subject: [PATCH 03/13] [SoundCloud] SoundCloudStreamExtractor.getTimeStamp
return 0 if no timestamp in url
---
.../soundcloud/extractors/SoundcloudStreamExtractor.java | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/soundcloud/extractors/SoundcloudStreamExtractor.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/soundcloud/extractors/SoundcloudStreamExtractor.java
index 67cd533e9c..595862bde7 100644
--- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/soundcloud/extractors/SoundcloudStreamExtractor.java
+++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/soundcloud/extractors/SoundcloudStreamExtractor.java
@@ -121,7 +121,8 @@ public long getLength() {
@Override
public long getTimeStamp() throws ParsingException {
- return getTimestampSeconds("(#t=\\d{0,3}h?\\d{0,3}m?\\d{1,3}s?)");
+ final var timestamp = getTimestampSeconds("(#t=\\d{0,3}h?\\d{0,3}m?\\d{1,3}s?)");
+ return timestamp == -2 ? 0 : timestamp;
}
@Override
@@ -170,7 +171,7 @@ public List getAudioStreams() throws ExtractionException {
try {
final JsonArray transcodings = track.getObject("media")
- .getArray("transcodings");
+ .getArray("transcodings");
if (!isNullOrEmpty(transcodings)) {
// Get information about what stream formats are available
extractAudioStreams(transcodings, audioStreams);
From 41b77ef2ac7f30274eae6800d66c33432aee4b9d Mon Sep 17 00:00:00 2001
From: David Asunmo <22662897+davidasunmo@users.noreply.github.com.>
Date: Wed, 4 Jun 2025 05:18:19 +0100
Subject: [PATCH 04/13] Fix typo
---
.../src/main/java/org/schabi/newpipe/extractor/utils/Utils.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/utils/Utils.java b/extractor/src/main/java/org/schabi/newpipe/extractor/utils/Utils.java
index c061ce30fa..12e0069f31 100644
--- a/extractor/src/main/java/org/schabi/newpipe/extractor/utils/Utils.java
+++ b/extractor/src/main/java/org/schabi/newpipe/extractor/utils/Utils.java
@@ -115,7 +115,7 @@ public static void checkUrl(final String pattern, final String url) throws Parsi
}
if (!Parser.isMatch(pattern, url.toLowerCase())) {
- throw new ParsingException("Url don't match the pattern");
+ throw new ParsingException("Url doesn't match the pattern");
}
}
From 8114af4c01e1e76ceca3f88cac829f69cd4699d3 Mon Sep 17 00:00:00 2001
From: David Asunmo <22662897+davidasunmo@users.noreply.github.com.>
Date: Sat, 7 Jun 2025 08:22:55 +0100
Subject: [PATCH 05/13] [Localization] Add toString to DateWrapper for better
debugging
---
.../newpipe/extractor/localization/DateWrapper.java | 8 ++++++++
1 file changed, 8 insertions(+)
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 ffc29a61ce..2f0a2bdd2a 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
@@ -69,4 +69,12 @@ public OffsetDateTime offsetDateTime() {
public boolean isApproximation() {
return isApproximation;
}
+
+ @Override
+ public String toString() {
+ return "DateWrapper{"
+ + "offsetDateTime=" + offsetDateTime
+ + ", isApproximation=" + isApproximation
+ + '}';
+ }
}
From 89dab90aa70094db3f250af00cd06fd9b68e0e06 Mon Sep 17 00:00:00 2001
From: David Asunmo <22662897+davidasunmo@users.noreply.github.com.>
Date: Sun, 8 Jun 2025 11:49:10 +0100
Subject: [PATCH 06/13] [SoundCloud] Use Pattern instead of string for regex in
SoundcloudStreamLinkHandlerFactory Use non-capturing groups in regex Refactor
Parser.java Add more utility methods (will be used in later commits)
---
.../SoundcloudStreamLinkHandlerFactory.java | 19 +++-
.../newpipe/extractor/utils/Parser.java | 105 +++++++++++++-----
.../schabi/newpipe/extractor/utils/Utils.java | 10 ++
3 files changed, 102 insertions(+), 32 deletions(-)
diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/soundcloud/linkHandler/SoundcloudStreamLinkHandlerFactory.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/soundcloud/linkHandler/SoundcloudStreamLinkHandlerFactory.java
index e7809c52a1..421022ef0a 100644
--- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/soundcloud/linkHandler/SoundcloudStreamLinkHandlerFactory.java
+++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/soundcloud/linkHandler/SoundcloudStreamLinkHandlerFactory.java
@@ -1,5 +1,7 @@
package org.schabi.newpipe.extractor.services.soundcloud.linkHandler;
+import java.util.regex.Pattern;
+
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.linkhandler.LinkHandlerFactory;
import org.schabi.newpipe.extractor.services.soundcloud.SoundcloudParsingHelper;
@@ -9,11 +11,18 @@
public final class SoundcloudStreamLinkHandlerFactory extends LinkHandlerFactory {
private static final SoundcloudStreamLinkHandlerFactory INSTANCE
= new SoundcloudStreamLinkHandlerFactory();
- private static final String URL_PATTERN = "^https?://(www\\.|m\\.|on\\.)?"
- + "soundcloud.com/[0-9a-z_-]+"
- + "/(?!(tracks|albums|sets|reposts|followers|following)/?$)[0-9a-z_-]+/?([#?].*)?$";
- private static final String API_URL_PATTERN = "^https?://api-v2\\.soundcloud.com"
- + "/(tracks|albums|sets|reposts|followers|following)/([0-9a-z_-]+)/";
+
+ private static final Pattern URL_PATTERN = Pattern.compile(
+ "^https?://(?:www\\.|m\\.|on\\.)?"
+ + "soundcloud.com/[0-9a-z_-]+"
+ + "/(?!(?:tracks|albums|sets|reposts|followers|following)/?$)[0-9a-z_-]+/?(?:[#?].*)?$"
+ );
+
+ private static final Pattern API_URL_PATTERN = Pattern.compile(
+ "^https?://api-v2\\.soundcloud.com"
+ + "/(tracks|albums|sets|reposts|followers|following)/([0-9a-z_-]+)/"
+ );
+
private SoundcloudStreamLinkHandlerFactory() {
}
diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/utils/Parser.java b/extractor/src/main/java/org/schabi/newpipe/extractor/utils/Parser.java
index 325867e75d..ddda97bee6 100644
--- a/extractor/src/main/java/org/schabi/newpipe/extractor/utils/Parser.java
+++ b/extractor/src/main/java/org/schabi/newpipe/extractor/utils/Parser.java
@@ -44,38 +44,83 @@ public RegexException(final String message) {
}
}
+ @Nonnull
+ public static Matcher matchOrThrow(@Nonnull final Pattern pattern,
+ final String input) throws RegexException {
+ final Matcher matcher = pattern.matcher(input);
+ if (matcher.find()) {
+ return matcher;
+ } else {
+ String errorMessage = "Failed to find pattern \"" + pattern.pattern() + "\"";
+ if (input.length() <= 1024) {
+ errorMessage += " inside of \"" + input + "\"";
+ }
+ throw new RegexException(errorMessage);
+ }
+ }
+
+ @Nonnull
+ public static String matchNamedGroup(final String pattern,
+ final String input,
+ final String groupName) throws RegexException {
+ return matchNamedGroup(Pattern.compile(pattern), input, groupName);
+ }
+
+ @Nonnull
+ public static String matchNamedGroup(@Nonnull final Pattern pattern,
+ final String input,
+ @Nonnull final String groupName) throws RegexException {
+ return matchOrThrow(pattern, input).group(groupName);
+ }
+
+ public static int getStartIndexOfNamedGroup(@Nonnull final Pattern pattern,
+ final String input,
+ @Nonnull final String groupName)
+ throws RegexException {
+ return matchOrThrow(pattern, input).start(groupName);
+ }
+
+ public static int getEndIndexOfNamedGroup(@Nonnull final Pattern pattern,
+ final String input,
+ @Nonnull final String groupName)
+ throws RegexException {
+ return matchOrThrow(pattern, input).end(groupName);
+ }
+
+ @Nonnull
public static String matchGroup1(final String pattern, final String input)
throws RegexException {
return matchGroup(pattern, input, 1);
}
+
+ @Nonnull
public static String matchGroup1(final Pattern pattern,
- final String input) throws RegexException {
+ final String input) throws RegexException {
return matchGroup(pattern, input, 1);
}
-
+
+ /**
+ * Matches the specified group of the given pattern against the input.
+ *
+ * @param pattern The regex pattern to match.
+ * @param input The input string to match against.
+ * @param group The group number to retrieve (1-based index).
+ * @return The matching group as a string.
+ * @throws RegexException If the pattern does not match the input or if the group is not found.
+ */
+ @Nonnull
public static String matchGroup(final String pattern,
- final String input,
- final int group) throws RegexException {
+ final String input,
+ final int group) throws RegexException {
return matchGroup(Pattern.compile(pattern), input, group);
}
-
- public static String matchGroup(@Nonnull final Pattern pat,
+
+ @Nonnull
+ public static String matchGroup(@Nonnull final Pattern pattern,
final String input,
final int group) throws RegexException {
- final Matcher matcher = pat.matcher(input);
- final boolean foundMatch = matcher.find();
- if (foundMatch) {
- return matcher.group(group);
- } else {
- // only pass input to exception message when it is not too long
- if (input.length() > 1024) {
- throw new RegexException("Failed to find pattern \"" + pat.pattern() + "\"");
- } else {
- throw new RegexException("Failed to find pattern \"" + pat.pattern()
- + "\" inside of \"" + input + "\"");
- }
- }
+ return matchOrThrow(pattern, input).group(group);
}
public static String matchGroup1MultiplePatterns(final Pattern[] patterns, final String input)
@@ -83,11 +128,20 @@ public static String matchGroup1MultiplePatterns(final Pattern[] patterns, final
return matchMultiplePatterns(patterns, input).group(1);
}
+ /**
+ * Matches multiple patterns against the input string and
+ * returns the first successful matcher
+ *
+ * @param patterns The array of regex patterns to match.
+ * @param input The input string to match against.
+ * @return A {@code Matcher} for the first successful match.
+ * @throws RegexException If no patterns match the input or if {@code patterns} is empty.
+ */
public static Matcher matchMultiplePatterns(final Pattern[] patterns, final String input)
throws RegexException {
- Parser.RegexException exception = null;
- for (final Pattern pattern : patterns) {
- final Matcher matcher = pattern.matcher(input);
+ RegexException exception = null;
+ for (final var pattern : patterns) {
+ final var matcher = pattern.matcher(input);
if (matcher.find()) {
return matcher;
} else if (exception == null) {
@@ -107,14 +161,11 @@ public static Matcher matchMultiplePatterns(final Pattern[] patterns, final Stri
}
public static boolean isMatch(final String pattern, final String input) {
- final Pattern pat = Pattern.compile(pattern);
- final Matcher mat = pat.matcher(input);
- return mat.find();
+ return isMatch(Pattern.compile(pattern), input);
}
public static boolean isMatch(@Nonnull final Pattern pattern, final String input) {
- final Matcher mat = pattern.matcher(input);
- return mat.find();
+ return pattern.matcher(input).find();
}
@Nonnull
diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/utils/Utils.java b/extractor/src/main/java/org/schabi/newpipe/extractor/utils/Utils.java
index 12e0069f31..bdf6bf20a2 100644
--- a/extractor/src/main/java/org/schabi/newpipe/extractor/utils/Utils.java
+++ b/extractor/src/main/java/org/schabi/newpipe/extractor/utils/Utils.java
@@ -110,6 +110,16 @@ public static long mixedNumberWordToLong(final String numberWord)
* @param url the url to be tested
*/
public static void checkUrl(final String pattern, final String url) throws ParsingException {
+ checkUrl(Pattern.compile(pattern), url);
+ }
+
+ /**
+ * Check if the url matches the pattern.
+ *
+ * @param pattern the pattern that will be used to check the url
+ * @param url the url to be tested
+ */
+ public static void checkUrl(final Pattern pattern, final String url) throws ParsingException {
if (isNullOrEmpty(url)) {
throw new IllegalArgumentException("Url can't be null or empty");
}
From ffb7c48e8af55752bc232100dfea79ac82634649 Mon Sep 17 00:00:00 2001
From: David Asunmo <22662897+davidasunmo@users.noreply.github.com.>
Date: Sun, 8 Jun 2025 15:47:24 +0100
Subject: [PATCH 07/13] Refactor Description constructor
---
.../org/schabi/newpipe/extractor/stream/Description.java | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/stream/Description.java b/extractor/src/main/java/org/schabi/newpipe/extractor/stream/Description.java
index 2641815b12..439609a2c1 100644
--- a/extractor/src/main/java/org/schabi/newpipe/extractor/stream/Description.java
+++ b/extractor/src/main/java/org/schabi/newpipe/extractor/stream/Description.java
@@ -17,11 +17,7 @@ public class Description implements Serializable {
public Description(@Nullable final String content, final int type) {
this.type = type;
- if (content == null) {
- this.content = "";
- } else {
- this.content = content;
- }
+ this.content = Objects.requireNonNullElse(content, "");
}
public String getContent() {
From ea00238df699903b118f2a953f18017da979fa7e Mon Sep 17 00:00:00 2001
From: David Asunmo <22662897+davidasunmo@users.noreply.github.com.>
Date: Tue, 8 Jul 2025 07:13:11 +0100
Subject: [PATCH 08/13] Remove redundant initialization
---
.../org/schabi/newpipe/extractor/stream/StreamInfo.java | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/stream/StreamInfo.java b/extractor/src/main/java/org/schabi/newpipe/extractor/stream/StreamInfo.java
index b54c69afc2..21d07cd94a 100644
--- a/extractor/src/main/java/org/schabi/newpipe/extractor/stream/StreamInfo.java
+++ b/extractor/src/main/java/org/schabi/newpipe/extractor/stream/StreamInfo.java
@@ -352,7 +352,7 @@ private static void extractOptionalData(final StreamInfo streamInfo,
private String uploaderUrl = "";
@Nonnull
private List uploaderAvatars = List.of();
- private boolean uploaderVerified = false;
+ private boolean uploaderVerified;
private long uploaderSubscriberCount = -1;
private String subChannelName = "";
@@ -368,7 +368,7 @@ private static void extractOptionalData(final StreamInfo streamInfo,
private String hlsUrl = "";
private List relatedItems = List.of();
- private long startPosition = 0;
+ private long startPosition;
private List subtitles = List.of();
private String host = "";
@@ -376,11 +376,11 @@ private static void extractOptionalData(final StreamInfo streamInfo,
private String category = "";
private String licence = "";
private String supportInfo = "";
- private Locale language = null;
+ private Locale language;
private List tags = List.of();
private List streamSegments = List.of();
private List metaInfo = List.of();
- private boolean shortFormContent = false;
+ private boolean shortFormContent;
/**
* Preview frames, e.g. for the storyboard / seekbar thumbnail preview
From 05d951b2fce570d313e8a4311882efb3f40cfb3b Mon Sep 17 00:00:00 2001
From: David Asunmo <22662897+davidasunmo@users.noreply.github.com.>
Date: Tue, 8 Jul 2025 07:19:20 +0100
Subject: [PATCH 09/13] Remove matchNamedGroup methods from Parser.java as not
available on Android API < 26
---
.../newpipe/extractor/utils/Parser.java | 87 ++++++++++---------
1 file changed, 48 insertions(+), 39 deletions(-)
diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/utils/Parser.java b/extractor/src/main/java/org/schabi/newpipe/extractor/utils/Parser.java
index ddda97bee6..962d3f9478 100644
--- a/extractor/src/main/java/org/schabi/newpipe/extractor/utils/Parser.java
+++ b/extractor/src/main/java/org/schabi/newpipe/extractor/utils/Parser.java
@@ -59,49 +59,39 @@ public static Matcher matchOrThrow(@Nonnull final Pattern pattern,
}
}
- @Nonnull
- public static String matchNamedGroup(final String pattern,
- final String input,
- final String groupName) throws RegexException {
- return matchNamedGroup(Pattern.compile(pattern), input, groupName);
- }
-
- @Nonnull
- public static String matchNamedGroup(@Nonnull final Pattern pattern,
- final String input,
- @Nonnull final String groupName) throws RegexException {
- return matchOrThrow(pattern, input).group(groupName);
- }
-
- public static int getStartIndexOfNamedGroup(@Nonnull final Pattern pattern,
- final String input,
- @Nonnull final String groupName)
- throws RegexException {
- return matchOrThrow(pattern, input).start(groupName);
- }
-
- public static int getEndIndexOfNamedGroup(@Nonnull final Pattern pattern,
- final String input,
- @Nonnull final String groupName)
- throws RegexException {
- return matchOrThrow(pattern, input).end(groupName);
- }
-
+ /**
+ * Matches group 1 of the given pattern against the input
+ * and returns the matched group
+ *
+ * @param pattern The regex pattern to match.
+ * @param input The input string to match against.
+ * @return The matching group as a string.
+ * @throws RegexException If the pattern does not match the input or if the group is not found.
+ */
@Nonnull
public static String matchGroup1(final String pattern, final String input)
throws RegexException {
return matchGroup(pattern, input, 1);
}
-
+ /**
+ * Matches group 1 of the given pattern against the input
+ * and returns the matched group
+ *
+ * @param pattern The regex pattern to match.
+ * @param input The input string to match against.
+ * @return The matching group as a string.
+ * @throws RegexException If the pattern does not match the input or if the group is not found.
+ */
@Nonnull
- public static String matchGroup1(final Pattern pattern,
- final String input) throws RegexException {
+ public static String matchGroup1(final Pattern pattern, final String input)
+ throws RegexException {
return matchGroup(pattern, input, 1);
}
-
+
/**
- * Matches the specified group of the given pattern against the input.
+ * Matches the specified group of the given pattern against the input,
+ * and returns the matched group
*
* @param pattern The regex pattern to match.
* @param input The input string to match against.
@@ -110,26 +100,45 @@ public static String matchGroup1(final Pattern pattern,
* @throws RegexException If the pattern does not match the input or if the group is not found.
*/
@Nonnull
- public static String matchGroup(final String pattern,
- final String input,
- final int group) throws RegexException {
+ public static String matchGroup(final String pattern, final String input, final int group)
+ throws RegexException {
return matchGroup(Pattern.compile(pattern), input, group);
}
-
+
+ /**
+ * Matches the specified group of the given pattern against the input,
+ * and returns the matched group
+ *
+ * @param pattern The regex pattern to match.
+ * @param input The input string to match against.
+ * @param group The group number to retrieve (1-based index).
+ * @return The matching group as a string.
+ * @throws RegexException If the pattern does not match the input or if the group is not found.
+ */
@Nonnull
public static String matchGroup(@Nonnull final Pattern pattern,
final String input,
- final int group) throws RegexException {
+ final int group)
+ throws RegexException {
return matchOrThrow(pattern, input).group(group);
}
+ /**
+ * Matches multiple patterns against the input string and
+ * returns the first successful matcher
+ *
+ * @param patterns The array of regex patterns to match.
+ * @param input The input string to match against.
+ * @return A {@code Matcher} for the first successful match.
+ * @throws RegexException If no patterns match the input or if {@code patterns} is empty.
+ */
public static String matchGroup1MultiplePatterns(final Pattern[] patterns, final String input)
throws RegexException {
return matchMultiplePatterns(patterns, input).group(1);
}
/**
- * Matches multiple patterns against the input string and
+ * Matches multiple patterns against the input string and
* returns the first successful matcher
*
* @param patterns The array of regex patterns to match.
From 93328a38e6d46ff27107c65b47ae87ed251f910a Mon Sep 17 00:00:00 2001
From: David Asunmo <22662897+davidasunmo@users.noreply.github.com.>
Date: Thu, 3 Jul 2025 05:25:25 +0100
Subject: [PATCH 10/13] Refactor AudioStream constructor to use builder instead
of explicit parameters. Refactor documentation also
---
.../newpipe/extractor/stream/AudioStream.java | 94 ++++++++-----------
1 file changed, 38 insertions(+), 56 deletions(-)
diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/stream/AudioStream.java b/extractor/src/main/java/org/schabi/newpipe/extractor/stream/AudioStream.java
index e31e1aff35..410a20592f 100644
--- a/extractor/src/main/java/org/schabi/newpipe/extractor/stream/AudioStream.java
+++ b/extractor/src/main/java/org/schabi/newpipe/extractor/stream/AudioStream.java
@@ -88,7 +88,8 @@ public Builder() {
}
/**
- * Set the identifier of the {@link AudioStream}.
+ * Set the identifier of the {@link AudioStream} which uniquely identifies the stream,
+ * e.g. for YouTube this would be the itag
*
*
* It must not be null and should be non empty.
@@ -108,14 +109,14 @@ public Builder setId(@Nonnull final String id) {
}
/**
- * Set the content of the {@link AudioStream}.
- *
+ * Set the content or the URL of the {@link AudioStream}, depending on whether isUrl is
+ * true
*
* It must not be null, and should be non empty.
*
*
* @param content the content of the {@link AudioStream}
- * @param isUrl whether the content is a URL
+ * @param isUrl whether content is the URL or the actual content of e.g. a DASH manifest
* @return this {@link Builder} instance
*/
public Builder setContent(@Nonnull final String content,
@@ -126,7 +127,7 @@ public Builder setContent(@Nonnull final String content,
}
/**
- * Set the {@link MediaFormat} used by the {@link AudioStream}.
+ * Set the {@link MediaFormat} used by the {@link AudioStream}, which can be null
*
*
* It should be one of the audio {@link MediaFormat}s ({@link MediaFormat#M4A M4A},
@@ -278,16 +279,22 @@ public Builder setItagItem(@Nullable final ItagItem itagItem) {
* Build an {@link AudioStream} using the builder's current values.
*
*
- * The identifier and the content (and so the {@code isUrl} boolean) properties must have
+ * The identifier and the content (and thus {@code isUrl}) properties must have
* been set.
*
*
* @return a new {@link AudioStream} using the builder's current values
- * @throws IllegalStateException if {@code id}, {@code content} (and so {@code isUrl}) or
+ * @throws IllegalStateException if {@code id}, {@code content} (and thus {@code isUrl}) or
* {@code deliveryMethod} have been not set, or have been set as {@code null}
*/
@Nonnull
public AudioStream build() {
+ validateBuild();
+
+ return new AudioStream(this);
+ }
+
+ void validateBuild() {
if (id == null) {
throw new IllegalStateException(
"The identifier of the audio stream has been not set or is null. If you "
@@ -305,64 +312,39 @@ public AudioStream build() {
"The delivery method of the audio stream has been set as null, which is "
+ "not allowed. Pass a valid one instead with setDeliveryMethod.");
}
-
- return new AudioStream(id, content, isUrl, mediaFormat, deliveryMethod, averageBitrate,
- manifestUrl, audioTrackId, audioTrackName, audioLocale, audioTrackType,
- itagItem);
}
}
/**
- * Create a new audio stream.
+ * Create a new audio stream using the given {@link Builder}.
*
- * @param id the identifier which uniquely identifies the stream, e.g. for YouTube
- * this would be the itag
- * @param content the content or the URL of the stream, depending on whether isUrl is
- * true
- * @param isUrl whether content is the URL or the actual content of e.g. a DASH
- * manifest
- * @param format the {@link MediaFormat} used by the stream, which can be null
- * @param deliveryMethod the {@link DeliveryMethod} of the stream
- * @param averageBitrate the average bitrate of the stream (which can be unknown, see
- * {@link #UNKNOWN_BITRATE})
- * @param audioTrackId the id of the audio track
- * @param audioTrackName the name of the audio track
- * @param audioLocale the {@link Locale} of the audio stream, representing its language
- * @param itagItem the {@link ItagItem} corresponding to the stream, which cannot be null
- * @param manifestUrl the URL of the manifest this stream comes from (if applicable,
- * otherwise null)
+ * @param builder The {@link Builder} to use to create the audio stream
*/
@SuppressWarnings("checkstyle:ParameterNumber")
- private AudioStream(@Nonnull final String id,
- @Nonnull final String content,
- final boolean isUrl,
- @Nullable final MediaFormat format,
- @Nonnull final DeliveryMethod deliveryMethod,
- final int averageBitrate,
- @Nullable final String manifestUrl,
- @Nullable final String audioTrackId,
- @Nullable final String audioTrackName,
- @Nullable final Locale audioLocale,
- @Nullable final AudioTrackType audioTrackType,
- @Nullable final ItagItem itagItem) {
- super(id, content, isUrl, format, deliveryMethod, manifestUrl);
- if (itagItem != null) {
- this.itagItem = itagItem;
- this.itag = itagItem.id;
- this.quality = itagItem.getQuality();
- this.bitrate = itagItem.getBitrate();
- this.initStart = itagItem.getInitStart();
- this.initEnd = itagItem.getInitEnd();
- this.indexStart = itagItem.getIndexStart();
- this.indexEnd = itagItem.getIndexEnd();
- this.codec = itagItem.getCodec();
+ AudioStream(final Builder builder) {
+ super(builder.id,
+ builder.content,
+ builder.isUrl,
+ builder.mediaFormat,
+ builder.deliveryMethod,
+ builder.manifestUrl);
+ if (builder.itagItem != null) {
+ this.itagItem = builder.itagItem;
+ this.itag = builder.itagItem.id;
+ this.quality = builder.itagItem.getQuality();
+ this.bitrate = builder.itagItem.getBitrate();
+ this.initStart = builder.itagItem.getInitStart();
+ this.initEnd = builder.itagItem.getInitEnd();
+ this.indexStart = builder.itagItem.getIndexStart();
+ this.indexEnd = builder.itagItem.getIndexEnd();
+ this.codec = builder.itagItem.getCodec();
}
- this.averageBitrate = averageBitrate;
- this.audioTrackId = audioTrackId;
- this.audioTrackName = audioTrackName;
- this.audioLocale = audioLocale;
- this.audioTrackType = audioTrackType;
+ this.averageBitrate = builder.averageBitrate;
+ this.audioTrackId = builder.audioTrackId;
+ this.audioTrackName = builder.audioTrackName;
+ this.audioLocale = builder.audioLocale;
+ this.audioTrackType = builder.audioTrackType;
}
/**
From 73d93f83152538e29fcf73a809f807ed404bccae Mon Sep 17 00:00:00 2001
From: David Asunmo <22662897+davidasunmo@users.noreply.github.com.>
Date: Tue, 8 Jul 2025 07:23:58 +0100
Subject: [PATCH 11/13] List.of IDE suggestions refactoring
---
.../java/org/schabi/newpipe/downloader/DownloaderTestImpl.java | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/extractor/src/test/java/org/schabi/newpipe/downloader/DownloaderTestImpl.java b/extractor/src/test/java/org/schabi/newpipe/downloader/DownloaderTestImpl.java
index 091db071d0..6fd0c4c7cc 100644
--- a/extractor/src/test/java/org/schabi/newpipe/downloader/DownloaderTestImpl.java
+++ b/extractor/src/test/java/org/schabi/newpipe/downloader/DownloaderTestImpl.java
@@ -7,7 +7,6 @@
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;
import java.io.IOException;
-import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@@ -35,7 +34,7 @@ private DownloaderTestImpl(final OkHttpClient.Builder builder) {
// Required for certain services
// For example Bandcamp otherwise fails on Windows with Java 17+
// as their Fastly-CDN returns 403
- .connectionSpecs(Arrays.asList(ConnectionSpec.RESTRICTED_TLS))
+ .connectionSpecs(List.of(ConnectionSpec.RESTRICTED_TLS))
.build());
}
From 5066141be008ed0e3c5d6fc39ff62786531350e0 Mon Sep 17 00:00:00 2001
From: David Asunmo <22662897+davidasunmo@users.noreply.github.com.>
Date: Tue, 8 Jul 2025 08:17:08 +0100
Subject: [PATCH 12/13] CamelCase typo
---
.../extractor/services/youtube/search/YoutubeSearchQHTest.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/search/YoutubeSearchQHTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/search/YoutubeSearchQHTest.java
index b007f6ddc0..f7f1d95d1d 100644
--- a/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/search/YoutubeSearchQHTest.java
+++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/search/YoutubeSearchQHTest.java
@@ -43,7 +43,7 @@ public void testGetContentFilter() throws Exception {
}
@Test
- public void testWithContentfilter() throws Exception {
+ public void testWithContentFilter() throws Exception {
assertEquals("https://www.youtube.com/results?search_query=asdf&sp=EgIQAfABAQ%253D%253D", YouTube.getSearchQHFactory()
.fromQuery("asdf", List.of(VIDEOS), "").getUrl());
assertEquals("https://www.youtube.com/results?search_query=asdf&sp=EgIQAvABAQ%253D%253D", YouTube.getSearchQHFactory()
From 25113b2453f9d584272c9e522dc66411ed5d0a2e Mon Sep 17 00:00:00 2001
From: David Asunmo <22662897+davidasunmo@users.noreply.github.com.>
Date: Tue, 8 Jul 2025 12:48:05 +0100
Subject: [PATCH 13/13] Minor refactoring in Stream.java
---
.../org/schabi/newpipe/extractor/stream/Stream.java | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/stream/Stream.java b/extractor/src/main/java/org/schabi/newpipe/extractor/stream/Stream.java
index 04d2b3facb..57e824560d 100644
--- a/extractor/src/main/java/org/schabi/newpipe/extractor/stream/Stream.java
+++ b/extractor/src/main/java/org/schabi/newpipe/extractor/stream/Stream.java
@@ -68,7 +68,7 @@ public Stream(final String id,
* @param streamList the list of {@link Stream}s which will be compared
* @return whether the list already contains one stream with equals stats
*/
- public static boolean containSimilarStream(final Stream stream,
+ public static boolean containSimilarStream(@Nonnull final Stream stream,
final List extends Stream> streamList) {
if (isNullOrEmpty(streamList)) {
return false;
@@ -98,11 +98,9 @@ public static boolean containSimilarStream(final Stream stream,
* @return whether the stream have the same stats or not, based on the criteria above
*/
public boolean equalStats(@Nullable final Stream other) {
- if (other == null || mediaFormat == null || other.mediaFormat == null) {
- return false;
- }
- return mediaFormat.id == other.mediaFormat.id && deliveryMethod == other.deliveryMethod
- && isUrl == other.isUrl;
+ return other != null && mediaFormat != null && other.mediaFormat != null
+ && mediaFormat.id == other.mediaFormat.id && deliveryMethod == other.deliveryMethod
+ && isUrl == other.isUrl;
}
/**
@@ -137,6 +135,7 @@ public String getUrl() {
*
* @return the content or URL
*/
+ @Nonnull
public String getContent() {
return content;
}