Allow checking for ContentAvailability

Adds a new field to `StreamInfoItem` to denote the availability of the
stream. A stream may be restricted to only certain user groups or times.

This allows users to ignore the stream based on their availability, e.g.
a app may choose to hide all streams that require payment.
pr1280
FineFindus 2025-03-17 20:13:09 +01:00 zatwierdzone przez Stypox
rodzic 51a247b059
commit cc8edec341
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4BDF1B40A49FDD23
7 zmienionych plików z 74 dodań i 27 usunięć

Wyświetl plik

@ -35,6 +35,7 @@ import org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper;
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeStreamLinkHandlerFactory;
import org.schabi.newpipe.extractor.stream.StreamInfoItemExtractor;
import org.schabi.newpipe.extractor.stream.StreamType;
import org.schabi.newpipe.extractor.stream.StreamInfoItem.ContentAvailability;
import org.schabi.newpipe.extractor.utils.JsonUtils;
import org.schabi.newpipe.extractor.utils.Parser;
import org.schabi.newpipe.extractor.utils.Utils;
@ -471,9 +472,7 @@ public class YoutubeStreamInfoItemExtractor implements StreamInfoItemExtractor {
}
}
@Nonnull
@Override
public boolean requiresMembership() throws ParsingException {
private boolean isMembersOnly() throws ParsingException {
final JsonArray badges = videoInfo.getArray("badges");
for (final Object badge : badges) {
if (((JsonObject) badge).getObject("metadataBadgeRenderer")
@ -484,4 +483,23 @@ public class YoutubeStreamInfoItemExtractor implements StreamInfoItemExtractor {
return false;
}
@Nonnull
@Override
public ContentAvailability getContentAvailability() throws ParsingException {
if (isPremiere()) {
return ContentAvailability.UPCOMING;
}
if (isMembersOnly()) {
return ContentAvailability.MEMBERSHIP;
}
if (isPremium()) {
return ContentAvailability.PAID;
}
return ContentAvailability.AVAILABLE;
}
}

Wyświetl plik

@ -33,6 +33,7 @@ import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.linkhandler.LinkHandler;
import org.schabi.newpipe.extractor.localization.DateWrapper;
import org.schabi.newpipe.extractor.stream.StreamInfoItem.ContentAvailability;
import org.schabi.newpipe.extractor.utils.Parser;
import javax.annotation.Nonnull;
@ -582,13 +583,13 @@ public abstract class StreamExtractor extends Extractor {
}
/**
* Whether the stream is only available to channel members.
* Get the availability of the stream.
*
* @return whether the stream is only available to channel members.
* @return The stream's availability
* @throws ParsingException if there is an error in the extraction
*/
public boolean requiresMembership() throws ParsingException {
return false;
public ContentAvailability getContentAvailability() throws ParsingException {
return ContentAvailability.AVAILABLE;
}
public enum Privacy {

Wyświetl plik

@ -26,6 +26,7 @@ import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.MetaInfo;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.stream.StreamInfoItem.ContentAvailability;
import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException;
import org.schabi.newpipe.extractor.exceptions.ContentNotSupportedException;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
@ -331,7 +332,7 @@ public class StreamInfo extends Info {
streamInfo.addError(e);
}
try {
streamInfo.setRequiresMembership(extractor.requiresMembership());
streamInfo.setContentAvailability(extractor.getContentAvailability());
} catch (final Exception e) {
streamInfo.addError(e);
}
@ -386,7 +387,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;
private ContentAvailability contentAvailability = ContentAvailability.AVAILABLE;
/**
* Preview frames, e.g. for the storyboard / seekbar thumbnail preview
@ -734,11 +735,11 @@ public class StreamInfo extends Info {
this.shortFormContent = isShortFormContent;
}
public boolean requiresMembership() {
return membersOnly;
public ContentAvailability getContentAvailability() {
return contentAvailability;
}
public void setRequiresMembership(final boolean requiresMembership) {
this.membersOnly = requiresMembership;
public void setContentAvailability(final ContentAvailability availablility) {
this.contentAvailability = availablility;
}
}

Wyświetl plik

@ -47,7 +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;
private ContentAvailability contentAvailability = ContentAvailability.AVAILABLE;
public StreamInfoItem(final int serviceId,
final String url,
@ -145,19 +145,19 @@ public class StreamInfoItem extends InfoItem {
}
/**
* Whether the stream is only available to channel members.
* Gets the availablility of the content.
*
* @return whether the stream is only available to channel members.
* @return The availablility of the stream.
*/
public boolean requiresMembership() {
return requiresMembership;
public ContentAvailability getContentAvailability() {
return contentAvailability;
}
/**
* Sets whether the stream is only available to channel members.
* Sets the availablility of the Stream.
*/
public void setRequiresMembership(final boolean requiresMembership) {
this.requiresMembership = requiresMembership;
public void setContentAvailability(final ContentAvailability availablility) {
this.contentAvailability = availablility;
}
@Override
@ -177,4 +177,29 @@ public class StreamInfoItem extends InfoItem {
+ ", uploaderVerified='" + isUploaderVerified() + '\''
+ '}';
}
/**
* Availablility of the stream.
*
* A stream may be available to all, restricted to a certain user group
* or time.
*/
public enum ContentAvailability {
/**
* The stream is available to all users.
*/
AVAILABLE,
/**
* The stream is available to users whith a membership.
*/
MEMBERSHIP,
/**
* The stream is behind a paywall.
*/
PAID,
/**
* The stream is only available in the future.
*/
UPCOMING,
}
}

Wyświetl plik

@ -24,6 +24,7 @@ import org.schabi.newpipe.extractor.Image;
import org.schabi.newpipe.extractor.InfoItemExtractor;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.localization.DateWrapper;
import org.schabi.newpipe.extractor.stream.StreamInfoItem.ContentAvailability;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@ -149,12 +150,12 @@ public interface StreamInfoItemExtractor extends InfoItemExtractor {
}
/**
* Whether the stream is only available to channel members.
* Get the availability of the stream.
*
* @return whether the stream is only available to channel members.
* @return The stream's availability
* @throws ParsingException if there is an error in the extraction
*/
default boolean requiresMembership() throws ParsingException {
return false;
default ContentAvailability getContentAvailability() throws ParsingException {
return ContentAvailability.AVAILABLE;
}
}

Wyświetl plik

@ -104,7 +104,7 @@ public class StreamInfoItemsCollector
addError(e);
}
try {
resultItem.setRequiresMembership(extractor.requiresMembership());
resultItem.setContentAvailability(extractor.getContentAvailability());
} catch (final Exception e) {
addError(e);
}

Wyświetl plik

@ -25,6 +25,7 @@ import org.schabi.newpipe.extractor.services.DefaultSimpleExtractorTest;
import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubePlaylistExtractor;
import org.schabi.newpipe.extractor.stream.Description;
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.extractor.stream.StreamInfoItem.ContentAvailability;
import org.schabi.newpipe.extractor.utils.Utils;
import java.io.IOException;
@ -522,7 +523,7 @@ public class YoutubePlaylistExtractorTest {
.map(StreamInfoItem.class::cast)
.collect(Collectors.toUnmodifiableList());
final List<StreamInfoItem> membershipVideos = allItems.stream()
.filter(item -> !item.requiresMembership())
.filter(item -> item.getContentAvailability() != ContentAvailability.MEMBERSHIP)
.collect(Collectors.toUnmodifiableList());
assertFalse(allItems.isEmpty());