1
0
mirror of https://github.com/TeamNewPipe/NewPipeExtractor synced 2025-10-05 16:12:47 +02:00

[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: https://github.com/TeamNewPipe/NewPipe/issues/12040
Ref: https://github.com/TeamNewPipe/NewPipe/issues/12011
This commit is contained in:
FineFindus
2025-02-13 18:14:55 +01:00
committed by Stypox
parent ac500b6cd8
commit 1b6907ec03
6 changed files with 62 additions and 0 deletions

View File

@@ -470,4 +470,18 @@ public class YoutubeStreamInfoItemExtractor implements StreamInfoItemExtractor {
throw new ParsingException("Could not determine if this is short-form content", e);
}
}
@Nonnull
@Override
public boolean requiresMembership() throws ParsingException {
final JsonArray badges = videoInfo.getArray("badges");
for (final Object badge : badges) {
if (((JsonObject) badge).getObject("metadataBadgeRenderer")
.getString("style", "").equals("BADGE_STYLE_TYPE_MEMBERS_ONLY")) {
return true;
}
}
return false;
}
}

View File

@@ -581,6 +581,16 @@ public abstract class StreamExtractor extends Extractor {
return false;
}
/**
* Whether the stream is only available to channel members.
*
* @return whether the stream is only available to channel members.
* @throws ParsingException if there is an error in the extraction
*/
public boolean requiresMembership() throws ParsingException {
return false;
}
public enum Privacy {
PUBLIC,
UNLISTED,

View File

@@ -330,6 +330,11 @@ public class StreamInfo extends Info {
} catch (final Exception e) {
streamInfo.addError(e);
}
try {
streamInfo.setRequiresMembership(extractor.requiresMembership());
} catch (final Exception e) {
streamInfo.addError(e);
}
streamInfo.setRelatedItems(ExtractorHelper.getRelatedItemsOrLogError(streamInfo,
extractor));
@@ -381,6 +386,7 @@ public class StreamInfo extends Info {
private List<StreamSegment> streamSegments = List.of();
private List<MetaInfo> metaInfo = List.of();
private boolean shortFormContent = false;
private boolean membersOnly = false;
/**
* Preview frames, e.g. for the storyboard / seekbar thumbnail preview
@@ -727,4 +733,12 @@ public class StreamInfo extends Info {
public void setShortFormContent(final boolean isShortFormContent) {
this.shortFormContent = isShortFormContent;
}
public boolean requiresMembership() {
return membersOnly;
}
public void setRequiresMembership(final boolean requiresMembership) {
this.membersOnly = requiresMembership;
}
}

View File

@@ -47,6 +47,7 @@ public class StreamInfoItem extends InfoItem {
private List<Image> uploaderAvatars = List.of();
private boolean uploaderVerified = false;
private boolean shortFormContent = false;
private boolean requiresMembership = false;
public StreamInfoItem(final int serviceId,
final String url,
@@ -143,6 +144,14 @@ public class StreamInfoItem extends InfoItem {
this.shortFormContent = shortFormContent;
}
public boolean requiresMembership() {
return requiresMembership;
}
public void setRequiresMembership(final boolean requiresMembership) {
this.requiresMembership = requiresMembership;
}
@Override
public String toString() {
return "StreamInfoItem{"

View File

@@ -147,4 +147,14 @@ public interface StreamInfoItemExtractor extends InfoItemExtractor {
default boolean isShortFormContent() throws ParsingException {
return false;
}
/**
* Whether the stream is only available to channel members.
*
* @return whether the stream is only available to channel members.
* @throws ParsingException if there is an error in the extraction
*/
default boolean requiresMembership() throws ParsingException {
return false;
}
}

View File

@@ -103,6 +103,11 @@ public class StreamInfoItemsCollector
} catch (final Exception e) {
addError(e);
}
try {
resultItem.setRequiresMembership(extractor.requiresMembership());
} catch (final Exception e) {
addError(e);
}
return resultItem;
}