Solve some review comments
This commit is contained in:
parent
c33d392958
commit
044639c32b
5 changed files with 63 additions and 121 deletions
|
@ -5,6 +5,7 @@ import com.grack.nanojson.JsonObject;
|
||||||
import com.grack.nanojson.JsonParser;
|
import com.grack.nanojson.JsonParser;
|
||||||
import com.grack.nanojson.JsonParserException;
|
import com.grack.nanojson.JsonParserException;
|
||||||
import org.jsoup.Jsoup;
|
import org.jsoup.Jsoup;
|
||||||
|
import org.jsoup.nodes.Element;
|
||||||
import org.schabi.newpipe.extractor.MediaFormat;
|
import org.schabi.newpipe.extractor.MediaFormat;
|
||||||
import org.schabi.newpipe.extractor.NewPipe;
|
import org.schabi.newpipe.extractor.NewPipe;
|
||||||
import org.schabi.newpipe.extractor.StreamingService;
|
import org.schabi.newpipe.extractor.StreamingService;
|
||||||
|
@ -80,9 +81,11 @@ public class BandcampRadioStreamExtractor extends BandcampStreamExtractor {
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public String getUploaderName() {
|
public String getUploaderName() throws ParsingException {
|
||||||
return Jsoup.parse(showInfo.getString("image_caption"))
|
return Jsoup.parse(showInfo.getString("image_caption")).getElementsByTag("a").stream()
|
||||||
.getElementsByTag("a").first().text();
|
.map(Element::text)
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow(() -> new ParsingException("Could not get uploader name"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
|
|
@ -4,7 +4,7 @@ package org.schabi.newpipe.extractor.services.youtube;
|
||||||
* Streaming format types used by YouTube in their streams.
|
* Streaming format types used by YouTube in their streams.
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* It is different of {@link org.schabi.newpipe.extractor.stream.DeliveryMethod delivery methods}!
|
* It is different from {@link org.schabi.newpipe.extractor.stream.DeliveryMethod delivery methods}!
|
||||||
* </p>
|
* </p>
|
||||||
*/
|
*/
|
||||||
public enum DeliveryType {
|
public enum DeliveryType {
|
||||||
|
|
|
@ -83,59 +83,18 @@ public final class YoutubeDashManifestCreatorsUtils {
|
||||||
*/
|
*/
|
||||||
public static final String ALR_YES = "&alr=yes";
|
public static final String ALR_YES = "&alr=yes";
|
||||||
|
|
||||||
/**
|
// XML elements of DASH MPD manifests
|
||||||
* Constant which represents the {@code MPD} element of DASH manifests.
|
// see https://www.brendanlong.com/the-structure-of-an-mpeg-dash-mpd.html
|
||||||
*/
|
|
||||||
public static final String MPD = "MPD";
|
public static final String MPD = "MPD";
|
||||||
|
|
||||||
/**
|
|
||||||
* Constant which represents the {@code Period} element of DASH manifests.
|
|
||||||
*/
|
|
||||||
public static final String PERIOD = "Period";
|
public static final String PERIOD = "Period";
|
||||||
|
|
||||||
/**
|
|
||||||
* Constant which represents the {@code AdaptationSet} element of DASH manifests.
|
|
||||||
*/
|
|
||||||
public static final String ADAPTATION_SET = "AdaptationSet";
|
public static final String ADAPTATION_SET = "AdaptationSet";
|
||||||
|
|
||||||
/**
|
|
||||||
* Constant which represents the {@code Role} element of DASH manifests.
|
|
||||||
*/
|
|
||||||
public static final String ROLE = "Role";
|
public static final String ROLE = "Role";
|
||||||
|
|
||||||
/**
|
|
||||||
* Constant which represents the {@code Representation} element of DASH manifests.
|
|
||||||
*/
|
|
||||||
public static final String REPRESENTATION = "Representation";
|
public static final String REPRESENTATION = "Representation";
|
||||||
|
|
||||||
/**
|
|
||||||
* Constant which represents the {@code AudioChannelConfiguration} element of DASH manifests.
|
|
||||||
*/
|
|
||||||
public static final String AUDIO_CHANNEL_CONFIGURATION = "AudioChannelConfiguration";
|
public static final String AUDIO_CHANNEL_CONFIGURATION = "AudioChannelConfiguration";
|
||||||
|
|
||||||
/**
|
|
||||||
* Constant which represents the {@code SegmentTemplate} element of DASH manifests.
|
|
||||||
*/
|
|
||||||
public static final String SEGMENT_TEMPLATE = "SegmentTemplate";
|
public static final String SEGMENT_TEMPLATE = "SegmentTemplate";
|
||||||
|
|
||||||
/**
|
|
||||||
* Constant which represents the {@code SegmentTimeline} element of DASH manifests.
|
|
||||||
*/
|
|
||||||
public static final String SEGMENT_TIMELINE = "SegmentTimeline";
|
public static final String SEGMENT_TIMELINE = "SegmentTimeline";
|
||||||
|
|
||||||
/**
|
|
||||||
* Constant which represents the {@code SegmentBase} element of DASH manifests.
|
|
||||||
*/
|
|
||||||
public static final String BASE_URL = "BaseURL";
|
public static final String BASE_URL = "BaseURL";
|
||||||
|
|
||||||
/**
|
|
||||||
* Constant which represents the {@code SegmentBase} element of DASH manifests.
|
|
||||||
*/
|
|
||||||
public static final String SEGMENT_BASE = "SegmentBase";
|
public static final String SEGMENT_BASE = "SegmentBase";
|
||||||
|
|
||||||
/**
|
|
||||||
* Constant which represents the {@code Initialization} element of DASH manifests.
|
|
||||||
*/
|
|
||||||
public static final String INITIALIZATION = "Initialization";
|
public static final String INITIALIZATION = "Initialization";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -665,7 +624,7 @@ public final class YoutubeDashManifestCreatorsUtils {
|
||||||
if (isHtml5StreamingUrl) {
|
if (isHtml5StreamingUrl) {
|
||||||
baseStreamingUrl += ALR_YES;
|
baseStreamingUrl += ALR_YES;
|
||||||
}
|
}
|
||||||
baseStreamingUrl = appendRnParamAndSqParamIfNeeded(baseStreamingUrl, deliveryType);
|
baseStreamingUrl = appendRnSqParamsIfNeeded(baseStreamingUrl, deliveryType);
|
||||||
|
|
||||||
final Downloader downloader = NewPipe.getDownloader();
|
final Downloader downloader = NewPipe.getDownloader();
|
||||||
if (isHtml5StreamingUrl) {
|
if (isHtml5StreamingUrl) {
|
||||||
|
@ -701,7 +660,7 @@ public final class YoutubeDashManifestCreatorsUtils {
|
||||||
* {@link XMLConstants#ACCESS_EXTERNAL_SCHEMA} in {@link DocumentBuilderFactory} instances.
|
* {@link XMLConstants#ACCESS_EXTERNAL_SCHEMA} in {@link DocumentBuilderFactory} instances.
|
||||||
*
|
*
|
||||||
* @return an instance of {@link Document} secured against XXE attacks on supported platforms,
|
* @return an instance of {@link Document} secured against XXE attacks on supported platforms,
|
||||||
* that should then be convertible to an XML string without security problems
|
* that should then be convertible to an XML string without security problems
|
||||||
*/
|
*/
|
||||||
private static Document newDocument() throws ParserConfigurationException {
|
private static Document newDocument() throws ParserConfigurationException {
|
||||||
final DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
|
final DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
|
||||||
|
@ -709,8 +668,8 @@ public final class YoutubeDashManifestCreatorsUtils {
|
||||||
documentBuilderFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
|
documentBuilderFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
|
||||||
documentBuilderFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
|
documentBuilderFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
|
||||||
} catch (final Exception ignored) {
|
} catch (final Exception ignored) {
|
||||||
// Ignore exceptions as setting these attributes to secure XML generation is supported
|
// Ignore exceptions as setting these attributes to secure XML generation is not
|
||||||
// by all platforms (like the Android implementation)
|
// supported by all platforms (like the Android implementation)
|
||||||
}
|
}
|
||||||
|
|
||||||
final DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
|
final DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
|
||||||
|
@ -736,8 +695,8 @@ public final class YoutubeDashManifestCreatorsUtils {
|
||||||
transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
|
transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
|
||||||
transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
|
transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
|
||||||
} catch (final Exception ignored) {
|
} catch (final Exception ignored) {
|
||||||
// Ignore exceptions as setting these attributes to secure XML generation is supported
|
// Ignore exceptions as setting these attributes to secure XML generation is not
|
||||||
// by all platforms (like the Android implementation)
|
// supported by all platforms (like the Android implementation)
|
||||||
}
|
}
|
||||||
|
|
||||||
final Transformer transformer = transformerFactory.newTransformer();
|
final Transformer transformer = transformerFactory.newTransformer();
|
||||||
|
@ -759,16 +718,10 @@ public final class YoutubeDashManifestCreatorsUtils {
|
||||||
* @return the base streaming URL to which the param(s) are appended, depending on the
|
* @return the base streaming URL to which the param(s) are appended, depending on the
|
||||||
* {@link DeliveryType} of the stream
|
* {@link DeliveryType} of the stream
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings({"checkstyle:FinalParameters", "checkstyle:FinalLocalVariable"})
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
private static String appendRnParamAndSqParamIfNeeded(
|
private static String appendRnSqParamsIfNeeded(@Nonnull final String baseStreamingUrl,
|
||||||
@Nonnull String baseStreamingUrl,
|
@Nonnull final DeliveryType deliveryType) {
|
||||||
@Nonnull final DeliveryType deliveryType) {
|
return baseStreamingUrl + (deliveryType == DeliveryType.PROGRESSIVE ? "" : SQ_0) + RN_0;
|
||||||
if (deliveryType != DeliveryType.PROGRESSIVE) {
|
|
||||||
baseStreamingUrl += SQ_0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return baseStreamingUrl + RN_0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1140,17 +1140,11 @@ public class YoutubeStreamExtractor extends StreamExtractor {
|
||||||
return videoSecondaryInfoRenderer;
|
return videoSecondaryInfoRenderer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@FunctionalInterface
|
|
||||||
private interface StreamBuilderHelper<T extends Stream> {
|
|
||||||
@Nonnull
|
|
||||||
T buildStream(ItagInfo itagInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
private <T extends Stream> List<T> getItags(
|
private <T extends Stream> List<T> getItags(
|
||||||
final String streamingDataKey,
|
final String streamingDataKey,
|
||||||
final ItagItem.ItagType itagTypeWanted,
|
final ItagItem.ItagType itagTypeWanted,
|
||||||
final StreamBuilderHelper<T> streamBuilderHelper,
|
final java.util.function.Function<ItagInfo, T> streamBuilderHelper,
|
||||||
final String streamTypeExceptionMessage) throws ParsingException {
|
final String streamTypeExceptionMessage) throws ParsingException {
|
||||||
try {
|
try {
|
||||||
final List<ItagInfo> itagInfos = new ArrayList<>();
|
final List<ItagInfo> itagInfos = new ArrayList<>();
|
||||||
|
@ -1176,7 +1170,7 @@ public class YoutubeStreamExtractor extends StreamExtractor {
|
||||||
|
|
||||||
final List<T> streamList = new ArrayList<>();
|
final List<T> streamList = new ArrayList<>();
|
||||||
for (final ItagInfo itagInfo : itagInfos) {
|
for (final ItagInfo itagInfo : itagInfos) {
|
||||||
final T stream = streamBuilderHelper.buildStream(itagInfo);
|
final T stream = streamBuilderHelper.apply(itagInfo);
|
||||||
if (!Stream.containSimilarStream(stream, streamList)) {
|
if (!Stream.containSimilarStream(stream, streamList)) {
|
||||||
streamList.add(stream);
|
streamList.add(stream);
|
||||||
}
|
}
|
||||||
|
@ -1190,8 +1184,8 @@ public class YoutubeStreamExtractor extends StreamExtractor {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the {@link StreamBuilderHelper} which will be used to build {@link AudioStream}s in
|
* Get the stream builder helper which will be used to build {@link AudioStream}s in
|
||||||
* {@link #getItags(String, ItagItem.ItagType, StreamBuilderHelper, String)}
|
* {@link #getItags(String, ItagItem.ItagType, java.util.function.Function, String)}
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* The {@code StreamBuilderHelper} will set the following attributes in the
|
* The {@code StreamBuilderHelper} will set the following attributes in the
|
||||||
|
@ -1213,38 +1207,34 @@ public class YoutubeStreamExtractor extends StreamExtractor {
|
||||||
* Note that the {@link ItagItem} comes from an {@link ItagInfo} instance.
|
* Note that the {@link ItagItem} comes from an {@link ItagInfo} instance.
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* @return a {@link StreamBuilderHelper} to build {@link AudioStream}s
|
* @return a stream builder helper to build {@link AudioStream}s
|
||||||
*/
|
*/
|
||||||
@Nonnull
|
@Nonnull
|
||||||
private StreamBuilderHelper<AudioStream> getAudioStreamBuilderHelper() {
|
private java.util.function.Function<ItagInfo, AudioStream> getAudioStreamBuilderHelper() {
|
||||||
return new StreamBuilderHelper<AudioStream>() {
|
return (itagInfo) -> {
|
||||||
@Nonnull
|
final ItagItem itagItem = itagInfo.getItagItem();
|
||||||
@Override
|
final AudioStream.Builder builder = new AudioStream.Builder()
|
||||||
public AudioStream buildStream(@Nonnull final ItagInfo itagInfo) {
|
.setId(String.valueOf(itagItem.id))
|
||||||
final ItagItem itagItem = itagInfo.getItagItem();
|
.setContent(itagInfo.getContent(), itagInfo.getIsUrl())
|
||||||
final AudioStream.Builder builder = new AudioStream.Builder()
|
.setMediaFormat(itagItem.getMediaFormat())
|
||||||
.setId(String.valueOf(itagItem.id))
|
.setAverageBitrate(itagItem.getAverageBitrate())
|
||||||
.setContent(itagInfo.getContent(), itagInfo.getIsUrl())
|
.setItagItem(itagItem);
|
||||||
.setMediaFormat(itagItem.getMediaFormat())
|
|
||||||
.setAverageBitrate(itagItem.getAverageBitrate())
|
|
||||||
.setItagItem(itagItem);
|
|
||||||
|
|
||||||
if (streamType == StreamType.LIVE_STREAM
|
if (streamType == StreamType.LIVE_STREAM
|
||||||
|| streamType == StreamType.POST_LIVE_STREAM
|
|| streamType == StreamType.POST_LIVE_STREAM
|
||||||
|| !itagInfo.getIsUrl()) {
|
|| !itagInfo.getIsUrl()) {
|
||||||
// For YouTube videos on OTF streams and for all streams of post-live streams
|
// For YouTube videos on OTF streams and for all streams of post-live streams
|
||||||
// and live streams, only the DASH delivery method can be used.
|
// and live streams, only the DASH delivery method can be used.
|
||||||
builder.setDeliveryMethod(DeliveryMethod.DASH);
|
builder.setDeliveryMethod(DeliveryMethod.DASH);
|
||||||
}
|
|
||||||
|
|
||||||
return builder.build();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return builder.build();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the {@link StreamBuilderHelper} which will be used to build {@link VideoStream}s in
|
* Get the stream builder helper which will be used to build {@link VideoStream}s in
|
||||||
* {@link #getItags(String, ItagItem.ItagType, StreamBuilderHelper, String)}
|
* {@link #getItags(String, ItagItem.ItagType, java.util.function.Function, String)}
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* The {@code StreamBuilderHelper} will set the following attributes in the
|
* The {@code StreamBuilderHelper} will set the following attributes in the
|
||||||
|
@ -1272,37 +1262,33 @@ public class YoutubeStreamExtractor extends StreamExtractor {
|
||||||
* Note that the {@link ItagItem} comes from an {@link ItagInfo} instance.
|
* Note that the {@link ItagItem} comes from an {@link ItagInfo} instance.
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* @param areStreamsVideoOnly whether the {@link StreamBuilderHelper} will set the video
|
* @param areStreamsVideoOnly whether the stream builder helper will set the video
|
||||||
* streams as video-only streams
|
* streams as video-only streams
|
||||||
* @return a {@link StreamBuilderHelper} to build {@link VideoStream}s
|
* @return a stream builder helper to build {@link VideoStream}s
|
||||||
*/
|
*/
|
||||||
@Nonnull
|
@Nonnull
|
||||||
private StreamBuilderHelper<VideoStream> getVideoStreamBuilderHelper(
|
private java.util.function.Function<ItagInfo, VideoStream> getVideoStreamBuilderHelper(
|
||||||
final boolean areStreamsVideoOnly) {
|
final boolean areStreamsVideoOnly) {
|
||||||
return new StreamBuilderHelper<VideoStream>() {
|
return (itagInfo) -> {
|
||||||
@Nonnull
|
final ItagItem itagItem = itagInfo.getItagItem();
|
||||||
@Override
|
final VideoStream.Builder builder = new VideoStream.Builder()
|
||||||
public VideoStream buildStream(@Nonnull final ItagInfo itagInfo) {
|
.setId(String.valueOf(itagItem.id))
|
||||||
final ItagItem itagItem = itagInfo.getItagItem();
|
.setContent(itagInfo.getContent(), itagInfo.getIsUrl())
|
||||||
final VideoStream.Builder builder = new VideoStream.Builder()
|
.setMediaFormat(itagItem.getMediaFormat())
|
||||||
.setId(String.valueOf(itagItem.id))
|
.setIsVideoOnly(areStreamsVideoOnly)
|
||||||
.setContent(itagInfo.getContent(), itagInfo.getIsUrl())
|
.setItagItem(itagItem);
|
||||||
.setMediaFormat(itagItem.getMediaFormat())
|
|
||||||
.setIsVideoOnly(areStreamsVideoOnly)
|
|
||||||
.setItagItem(itagItem);
|
|
||||||
|
|
||||||
final String resolutionString = itagItem.getResolutionString();
|
final String resolutionString = itagItem.getResolutionString();
|
||||||
builder.setResolution(resolutionString != null ? resolutionString
|
builder.setResolution(resolutionString != null ? resolutionString
|
||||||
: EMPTY_STRING);
|
: EMPTY_STRING);
|
||||||
|
|
||||||
if (streamType != StreamType.VIDEO_STREAM || !itagInfo.getIsUrl()) {
|
if (streamType != StreamType.VIDEO_STREAM || !itagInfo.getIsUrl()) {
|
||||||
// For YouTube videos on OTF streams and for all streams of post-live streams
|
// For YouTube videos on OTF streams and for all streams of post-live streams
|
||||||
// and live streams, only the DASH delivery method can be used.
|
// and live streams, only the DASH delivery method can be used.
|
||||||
builder.setDeliveryMethod(DeliveryMethod.DASH);
|
builder.setDeliveryMethod(DeliveryMethod.DASH);
|
||||||
}
|
|
||||||
|
|
||||||
return builder.build();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return builder.build();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -114,7 +114,7 @@ public class StreamInfo extends Info {
|
||||||
final String name = extractor.getName();
|
final String name = extractor.getName();
|
||||||
final int ageLimit = extractor.getAgeLimit();
|
final int ageLimit = extractor.getAgeLimit();
|
||||||
|
|
||||||
// Suppress always-non-null warning as here we double-check it is really not null
|
// Suppress always-non-null warning as here we double-check it really is not null
|
||||||
//noinspection ConstantConditions
|
//noinspection ConstantConditions
|
||||||
if (streamType == StreamType.NONE
|
if (streamType == StreamType.NONE
|
||||||
|| isNullOrEmpty(url)
|
|| isNullOrEmpty(url)
|
||||||
|
|
Loading…
Reference in a new issue