[YouTube] Inline collectSegmentsData in YoutubeDashManifestCreator
This commit is contained in:
parent
3708ab9ed5
commit
4da05afe11
|
@ -1,5 +1,16 @@
|
||||||
package org.schabi.newpipe.extractor.services.youtube;
|
package org.schabi.newpipe.extractor.services.youtube;
|
||||||
|
|
||||||
|
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.addClientInfoHeaders;
|
||||||
|
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getAndroidUserAgent;
|
||||||
|
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getIosUserAgent;
|
||||||
|
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.isAndroidStreamingUrl;
|
||||||
|
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.isIosStreamingUrl;
|
||||||
|
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.isTvHtml5SimplyEmbeddedPlayerStreamingUrl;
|
||||||
|
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.isWebStreamingUrl;
|
||||||
|
import static org.schabi.newpipe.extractor.utils.Utils.EMPTY_STRING;
|
||||||
|
import static org.schabi.newpipe.extractor.utils.Utils.isBlank;
|
||||||
|
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
|
||||||
|
|
||||||
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.downloader.Downloader;
|
import org.schabi.newpipe.extractor.downloader.Downloader;
|
||||||
|
@ -12,6 +23,17 @@ import org.w3c.dom.DOMException;
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.xml.XMLConstants;
|
import javax.xml.XMLConstants;
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
|
@ -23,28 +45,6 @@ import javax.xml.transform.TransformerException;
|
||||||
import javax.xml.transform.TransformerFactory;
|
import javax.xml.transform.TransformerFactory;
|
||||||
import javax.xml.transform.dom.DOMSource;
|
import javax.xml.transform.dom.DOMSource;
|
||||||
import javax.xml.transform.stream.StreamResult;
|
import javax.xml.transform.stream.StreamResult;
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.StringWriter;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.addClientInfoHeaders;
|
|
||||||
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getAndroidUserAgent;
|
|
||||||
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getIosUserAgent;
|
|
||||||
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.isAndroidStreamingUrl;
|
|
||||||
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.isIosStreamingUrl;
|
|
||||||
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.isTvHtml5SimplyEmbeddedPlayerStreamingUrl;
|
|
||||||
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.isWebStreamingUrl;
|
|
||||||
import static org.schabi.newpipe.extractor.utils.Utils.EMPTY_STRING;
|
|
||||||
import static org.schabi.newpipe.extractor.utils.Utils.isBlank;
|
|
||||||
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class to generate DASH manifests from YouTube OTF, progressive and ended/post-live-DVR streams.
|
* Class to generate DASH manifests from YouTube OTF, progressive and ended/post-live-DVR streams.
|
||||||
|
@ -74,28 +74,6 @@ public final class YoutubeDashManifestCreator {
|
||||||
*/
|
*/
|
||||||
private static final int MAXIMUM_REDIRECT_COUNT = 20;
|
private static final int MAXIMUM_REDIRECT_COUNT = 20;
|
||||||
|
|
||||||
/**
|
|
||||||
* A list of durations of segments of an OTF stream.
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* This list is automatically cleared in the execution of
|
|
||||||
* {@link #fromOtfStreamingUrl(String, ItagItem, long)}, before the DASH
|
|
||||||
* manifest is converted to a string.
|
|
||||||
* </p>
|
|
||||||
*/
|
|
||||||
private static final List<Integer> SEGMENTS_DURATION = new ArrayList<>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A list of contiguous repetitions of durations of an OTF stream.
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* This list is automatically cleared in the execution of
|
|
||||||
* {@link #fromOtfStreamingUrl(String, ItagItem, long)}, before the DASH
|
|
||||||
* manifest is converted to a string.
|
|
||||||
* </p>
|
|
||||||
*/
|
|
||||||
private static final List<Integer> DURATION_REPETITIONS = new ArrayList<>();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cache of DASH manifests generated for OTF streams.
|
* Cache of DASH manifests generated for OTF streams.
|
||||||
*/
|
*/
|
||||||
|
@ -296,11 +274,7 @@ public final class YoutubeDashManifestCreator {
|
||||||
}
|
}
|
||||||
generateSegmentTemplateElement(document, realOtfBaseStreamingUrl, DeliveryType.OTF);
|
generateSegmentTemplateElement(document, realOtfBaseStreamingUrl, DeliveryType.OTF);
|
||||||
generateSegmentTimelineElement(document);
|
generateSegmentTimelineElement(document);
|
||||||
collectSegmentsData(segmentDuration);
|
generateSegmentElementsForOtfStreams(segmentDuration, document);
|
||||||
generateSegmentElementsForOtfStreams(document);
|
|
||||||
|
|
||||||
SEGMENTS_DURATION.clear();
|
|
||||||
DURATION_REPETITIONS.clear();
|
|
||||||
|
|
||||||
return buildAndCacheResult(otfBaseStreamingUrl, document, OTF_CACHE);
|
return buildAndCacheResult(otfBaseStreamingUrl, document, OTF_CACHE);
|
||||||
}
|
}
|
||||||
|
@ -721,35 +695,6 @@ public final class YoutubeDashManifestCreator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Collect all segments from an OTF stream, by parsing the string array which contains all the
|
|
||||||
* sequences.
|
|
||||||
*
|
|
||||||
* @param segmentDuration the string array which contains all the sequences extracted with the
|
|
||||||
* regular expression
|
|
||||||
*/
|
|
||||||
private static void collectSegmentsData(@Nonnull final String[] segmentDuration)
|
|
||||||
throws YoutubeDashManifestCreationException {
|
|
||||||
try {
|
|
||||||
for (final String segDuration : segmentDuration) {
|
|
||||||
final String[] segmentLengthRepeat = segDuration.split("\\(r=");
|
|
||||||
int segmentRepeatCount = 0;
|
|
||||||
// There are repetitions of a segment duration in other segments
|
|
||||||
if (segmentLengthRepeat.length > 1) {
|
|
||||||
segmentRepeatCount = Integer.parseInt(Utils.removeNonDigitCharacters(
|
|
||||||
segmentLengthRepeat[1]));
|
|
||||||
}
|
|
||||||
final int segmentLength = Integer.parseInt(segmentLengthRepeat[0]);
|
|
||||||
SEGMENTS_DURATION.add(segmentLength);
|
|
||||||
DURATION_REPETITIONS.add(segmentRepeatCount);
|
|
||||||
}
|
|
||||||
} catch (final NumberFormatException e) {
|
|
||||||
throw new YoutubeDashManifestCreationException(
|
|
||||||
"Could not generate the DASH manifest: unable to get the segments of the "
|
|
||||||
+ "stream", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the duration of an OTF stream.
|
* Get the duration of an OTF stream.
|
||||||
*
|
*
|
||||||
|
@ -1429,8 +1374,7 @@ public final class YoutubeDashManifestCreator {
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* By parsing by the first media sequence, we know how many durations and repetitions there are
|
* By parsing by the first media sequence, we know how many durations and repetitions there are
|
||||||
* so we just have to loop into {@link #SEGMENTS_DURATION} and {@link #DURATION_REPETITIONS}
|
* so we just have to loop into segment durations to generate the following elements for each:
|
||||||
* to generate the following element for each duration:
|
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -1451,36 +1395,43 @@ public final class YoutubeDashManifestCreator {
|
||||||
* {@link #generateSegmentTimelineElement(Document)}.
|
* {@link #generateSegmentTimelineElement(Document)}.
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
|
* @param segmentDurations the sequences "length" or "length(r=repeat_count" extracted with the
|
||||||
|
* regexes
|
||||||
* @param document the {@link Document} on which the the {@code <S>} elements will be appended
|
* @param document the {@link Document} on which the the {@code <S>} elements will be appended
|
||||||
*/
|
*/
|
||||||
private static void generateSegmentElementsForOtfStreams(@Nonnull final Document document)
|
private static void generateSegmentElementsForOtfStreams(final String[] segmentDurations,
|
||||||
|
final Document document)
|
||||||
throws YoutubeDashManifestCreationException {
|
throws YoutubeDashManifestCreationException {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (SEGMENTS_DURATION.isEmpty() || DURATION_REPETITIONS.isEmpty()) {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"Duration of segments and/or repetition(s) of segments are unknown");
|
|
||||||
}
|
|
||||||
final Element segmentTimelineElement = (Element) document.getElementsByTagName(
|
final Element segmentTimelineElement = (Element) document.getElementsByTagName(
|
||||||
"SegmentTimeline").item(0);
|
"SegmentTimeline").item(0);
|
||||||
|
|
||||||
for (int i = 0; i < SEGMENTS_DURATION.size(); i++) {
|
for (final String segmentDuration : segmentDurations) {
|
||||||
final Element sElement = document.createElement("S");
|
final Element sElement = document.createElement("S");
|
||||||
|
|
||||||
final int durationRepetition = DURATION_REPETITIONS.get(i);
|
final String[] segmentLengthRepeat = segmentDuration.split("\\(r=");
|
||||||
if (durationRepetition != 0) {
|
// make sure segmentLengthRepeat[0], which is the length, is convertible to int
|
||||||
|
Integer.parseInt(segmentLengthRepeat[0]);
|
||||||
|
|
||||||
|
// There are repetitions of a segment duration in other segments
|
||||||
|
if (segmentLengthRepeat.length > 1) {
|
||||||
|
final int segmentRepeatCount = Integer.parseInt(
|
||||||
|
Utils.removeNonDigitCharacters(segmentLengthRepeat[1]));
|
||||||
final Attr rAttribute = document.createAttribute("r");
|
final Attr rAttribute = document.createAttribute("r");
|
||||||
rAttribute.setValue(String.valueOf(durationRepetition));
|
rAttribute.setValue(String.valueOf(segmentRepeatCount));
|
||||||
sElement.setAttributeNode(rAttribute);
|
sElement.setAttributeNode(rAttribute);
|
||||||
}
|
}
|
||||||
|
|
||||||
final Attr dAttribute = document.createAttribute("d");
|
final Attr dAttribute = document.createAttribute("d");
|
||||||
dAttribute.setValue(String.valueOf(SEGMENTS_DURATION.get(i)));
|
dAttribute.setValue(segmentLengthRepeat[0]);
|
||||||
sElement.setAttributeNode(dAttribute);
|
sElement.setAttributeNode(dAttribute);
|
||||||
|
|
||||||
segmentTimelineElement.appendChild(sElement);
|
segmentTimelineElement.appendChild(sElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (final DOMException | IllegalStateException | IndexOutOfBoundsException e) {
|
} catch (final DOMException | IllegalStateException | IndexOutOfBoundsException
|
||||||
|
| NumberFormatException e) {
|
||||||
throw new YoutubeDashManifestCreationException(
|
throw new YoutubeDashManifestCreationException(
|
||||||
"Could not generate or append the segment (S) elements of the DASH manifest "
|
"Could not generate or append the segment (S) elements of the DASH manifest "
|
||||||
+ "to the document", e);
|
+ "to the document", e);
|
||||||
|
|
Loading…
Reference in New Issue