[YouTube] Inline collectSegmentsData in YoutubeDashManifestCreator

This commit is contained in:
Stypox 2022-05-01 18:23:00 +02:00 committed by TiA4f8R
parent 3708ab9ed5
commit 4da05afe11
No known key found for this signature in database
GPG Key ID: E6D3E7F5949450DD
1 changed files with 42 additions and 91 deletions

View File

@ -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);