Skip to content

Commit 601c1c8

Browse files
committedFeb 18, 2025
[Youtube] Mark members-only videos
YouTube inserts members-only videos (i.e., videos that require channel membership to watch) into the Videos tab. Because the extractor unable to distinguish between them and "normal" videos, they may appear in subscriptions feeds. This enables the extractor to check if videos require membership, allowing clients to filter them. Ref: TeamNewPipe/NewPipe#12040 Ref: TeamNewPipe/NewPipe#12011
1 parent aa67363 commit 601c1c8

File tree

6 files changed

+62
-0
lines changed

6 files changed

+62
-0
lines changed
 

‎extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeStreamInfoItemExtractor.java

+14
Original file line numberDiff line numberDiff line change
@@ -470,4 +470,18 @@ public boolean isShortFormContent() throws ParsingException {
470470
throw new ParsingException("Could not determine if this is short-form content", e);
471471
}
472472
}
473+
474+
@Nonnull
475+
@Override
476+
public boolean requiresMembership() throws ParsingException {
477+
final JsonArray badges = videoInfo.getArray("badges");
478+
for (final Object badge : badges) {
479+
if (((JsonObject) badge).getObject("metadataBadgeRenderer")
480+
.getString("style", "").equals("BADGE_STYLE_TYPE_MEMBERS_ONLY")) {
481+
return true;
482+
}
483+
}
484+
return false;
485+
}
486+
473487
}

‎extractor/src/main/java/org/schabi/newpipe/extractor/stream/StreamExtractor.java

+10
Original file line numberDiff line numberDiff line change
@@ -581,6 +581,16 @@ public boolean isShortFormContent() throws ParsingException {
581581
return false;
582582
}
583583

584+
/**
585+
* Whether the stream is only available to channel members.
586+
*
587+
* @return whether the stream is only available to channel members.
588+
* @throws ParsingException if there is an error in the extraction
589+
*/
590+
public boolean requiresMembership() throws ParsingException {
591+
return false;
592+
}
593+
584594
public enum Privacy {
585595
PUBLIC,
586596
UNLISTED,

‎extractor/src/main/java/org/schabi/newpipe/extractor/stream/StreamInfo.java

+14
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,11 @@ private static void extractOptionalData(final StreamInfo streamInfo,
330330
} catch (final Exception e) {
331331
streamInfo.addError(e);
332332
}
333+
try {
334+
streamInfo.setRequiresMembership(extractor.requiresMembership());
335+
} catch (final Exception e) {
336+
streamInfo.addError(e);
337+
}
333338

334339
streamInfo.setRelatedItems(ExtractorHelper.getRelatedItemsOrLogError(streamInfo,
335340
extractor));
@@ -381,6 +386,7 @@ private static void extractOptionalData(final StreamInfo streamInfo,
381386
private List<StreamSegment> streamSegments = List.of();
382387
private List<MetaInfo> metaInfo = List.of();
383388
private boolean shortFormContent = false;
389+
private boolean membersOnly = false;
384390

385391
/**
386392
* Preview frames, e.g. for the storyboard / seekbar thumbnail preview
@@ -727,4 +733,12 @@ public boolean isShortFormContent() {
727733
public void setShortFormContent(final boolean isShortFormContent) {
728734
this.shortFormContent = isShortFormContent;
729735
}
736+
737+
public boolean requiresMembership() {
738+
return membersOnly;
739+
}
740+
741+
public void setRequiresMembership(final boolean requiresMembership) {
742+
this.membersOnly = requiresMembership;
743+
}
730744
}

‎extractor/src/main/java/org/schabi/newpipe/extractor/stream/StreamInfoItem.java

+9
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ public class StreamInfoItem extends InfoItem {
4747
private List<Image> uploaderAvatars = List.of();
4848
private boolean uploaderVerified = false;
4949
private boolean shortFormContent = false;
50+
private boolean requiresMembership = false;
5051

5152
public StreamInfoItem(final int serviceId,
5253
final String url,
@@ -143,6 +144,14 @@ public void setShortFormContent(final boolean shortFormContent) {
143144
this.shortFormContent = shortFormContent;
144145
}
145146

147+
public boolean requiresMembership() {
148+
return requiresMembership;
149+
}
150+
151+
public void setRequiresMembership(final boolean requiresMembership) {
152+
this.requiresMembership = requiresMembership;
153+
}
154+
146155
@Override
147156
public String toString() {
148157
return "StreamInfoItem{"

‎extractor/src/main/java/org/schabi/newpipe/extractor/stream/StreamInfoItemExtractor.java

+10
Original file line numberDiff line numberDiff line change
@@ -146,4 +146,14 @@ default String getShortDescription() throws ParsingException {
146146
default boolean isShortFormContent() throws ParsingException {
147147
return false;
148148
}
149+
150+
/**
151+
* Whether the stream is only available to channel members.
152+
*
153+
* @return whether the stream is only available to channel members.
154+
* @throws ParsingException if there is an error in the extraction
155+
*/
156+
default boolean requiresMembership() throws ParsingException {
157+
return false;
158+
}
149159
}

‎extractor/src/main/java/org/schabi/newpipe/extractor/stream/StreamInfoItemsCollector.java

+5
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,11 @@ public StreamInfoItem extract(final StreamInfoItemExtractor extractor) throws Pa
103103
} catch (final Exception e) {
104104
addError(e);
105105
}
106+
try {
107+
resultItem.setRequiresMembership(extractor.requiresMembership());
108+
} catch (final Exception e) {
109+
addError(e);
110+
}
106111

107112
return resultItem;
108113
}

0 commit comments

Comments
 (0)
Please sign in to comment.