Remove unused DashMpdParser (but kept in git history)
This commit is contained in:
parent
50272db946
commit
159d05c91b
|
@ -1,244 +0,0 @@
|
|||
/*
|
||||
* Created by Christian Schabesberger on 02.02.16.
|
||||
*
|
||||
* Copyright (C) Christian Schabesberger 2016 <chris.schabesberger@mailbox.org>
|
||||
* DashMpdParser.java is part of NewPipe Extractor.
|
||||
*
|
||||
* NewPipe Extractor is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* NewPipe Extractor is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with NewPipe Extractor. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.schabi.newpipe.extractor.services.youtube;
|
||||
|
||||
import org.schabi.newpipe.extractor.MediaFormat;
|
||||
import org.schabi.newpipe.extractor.NewPipe;
|
||||
import org.schabi.newpipe.extractor.downloader.Downloader;
|
||||
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
||||
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;
|
||||
import org.schabi.newpipe.extractor.stream.AudioStream;
|
||||
import org.schabi.newpipe.extractor.stream.DeliveryMethod;
|
||||
import org.schabi.newpipe.extractor.stream.VideoStream;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.StringWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.transform.OutputKeys;
|
||||
import javax.xml.transform.Transformer;
|
||||
import javax.xml.transform.TransformerException;
|
||||
import javax.xml.transform.TransformerFactory;
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
|
||||
/**
|
||||
* Class to extract streams from a DASH manifest.
|
||||
*
|
||||
* <p>
|
||||
* Note that this class relies on the YouTube's {@link ItagItem} class and should be made generic
|
||||
* in order to be used on other services.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* This class is not used by the extractor itself, as all streams are supported by the extractor.
|
||||
* </p>
|
||||
*/
|
||||
public final class DashMpdParser {
|
||||
private DashMpdParser() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Exception class which is thrown when something went wrong when using
|
||||
* {@link DashMpdParser#getStreams(String)}.
|
||||
*/
|
||||
public static class DashMpdParsingException extends ParsingException {
|
||||
|
||||
DashMpdParsingException(final String message, final Exception e) {
|
||||
super(message, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class which represents the result of a DASH MPD file parsing by {@link DashMpdParser}.
|
||||
*
|
||||
* <p>
|
||||
* The result contains video, video-only and audio streams.
|
||||
* </p>
|
||||
*/
|
||||
public static class Result {
|
||||
private final List<VideoStream> videoStreams;
|
||||
private final List<VideoStream> videoOnlyStreams;
|
||||
private final List<AudioStream> audioStreams;
|
||||
|
||||
Result(final List<VideoStream> videoStreams,
|
||||
final List<VideoStream> videoOnlyStreams,
|
||||
final List<AudioStream> audioStreams) {
|
||||
this.videoStreams = videoStreams;
|
||||
this.videoOnlyStreams = videoOnlyStreams;
|
||||
this.audioStreams = audioStreams;
|
||||
}
|
||||
|
||||
public List<VideoStream> getVideoStreams() {
|
||||
return videoStreams;
|
||||
}
|
||||
|
||||
public List<VideoStream> getVideoOnlyStreams() {
|
||||
return videoOnlyStreams;
|
||||
}
|
||||
|
||||
public List<AudioStream> getAudioStreams() {
|
||||
return audioStreams;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will try to download and parse the YouTube DASH MPD manifest URL provided to get
|
||||
* supported {@link AudioStream}s and {@link VideoStream}s.
|
||||
*
|
||||
* <p>
|
||||
* The parser supports video, video-only and audio streams.
|
||||
* </p>
|
||||
*
|
||||
* @param dashMpdUrl the URL of the DASH MPD manifest
|
||||
* @return a {@link Result} which contains all video, video-only and audio streams extracted
|
||||
* and supported by the extractor (so the ones for which {@link ItagItem#isSupported(int)}
|
||||
* returns {@code true}).
|
||||
* @throws DashMpdParsingException if something went wrong when downloading or parsing the
|
||||
* manifest
|
||||
* @see <a href="https://www.brendanlong.com/the-structure-of-an-mpeg-dash-mpd.html">
|
||||
* www.brendanlong.com's page about the structure of an MPEG-DASH MPD manifest</a>
|
||||
*/
|
||||
@Nonnull
|
||||
public static Result getStreams(final String dashMpdUrl)
|
||||
throws DashMpdParsingException, ReCaptchaException {
|
||||
final String dashDoc;
|
||||
final Downloader downloader = NewPipe.getDownloader();
|
||||
try {
|
||||
dashDoc = downloader.get(dashMpdUrl).responseBody();
|
||||
} catch (final IOException e) {
|
||||
throw new DashMpdParsingException("Could not fetch DASH manifest: " + dashMpdUrl, e);
|
||||
}
|
||||
|
||||
try {
|
||||
final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||
final DocumentBuilder builder = factory.newDocumentBuilder();
|
||||
final InputStream stream = new ByteArrayInputStream(dashDoc.getBytes());
|
||||
|
||||
final Document doc = builder.parse(stream);
|
||||
final NodeList representationList = doc.getElementsByTagName("Representation");
|
||||
|
||||
final List<VideoStream> videoStreams = new ArrayList<>();
|
||||
final List<AudioStream> audioStreams = new ArrayList<>();
|
||||
final List<VideoStream> videoOnlyStreams = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < representationList.getLength(); i++) {
|
||||
final Element representation = (Element) representationList.item(i);
|
||||
try {
|
||||
final String mimeType = ((Element) representation.getParentNode())
|
||||
.getAttribute("mimeType");
|
||||
final String id = representation.getAttribute("id");
|
||||
final ItagItem itag = ItagItem.getItag(Integer.parseInt(id));
|
||||
final Element segmentationList = (Element) representation
|
||||
.getElementsByTagName("SegmentList").item(0);
|
||||
|
||||
if (segmentationList == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final MediaFormat mediaFormat = MediaFormat.getFromMimeType(mimeType);
|
||||
|
||||
if (itag.itagType.equals(ItagItem.ItagType.AUDIO)) {
|
||||
audioStreams.add(new AudioStream.Builder()
|
||||
.setId(String.valueOf(itag.id))
|
||||
.setContent(manualDashFromRepresentation(doc, representation),
|
||||
false)
|
||||
.setMediaFormat(mediaFormat)
|
||||
.setDeliveryMethod(DeliveryMethod.DASH)
|
||||
.setAverageBitrate(itag.getAverageBitrate())
|
||||
.setBaseUrl(dashMpdUrl)
|
||||
.setItagItem(itag)
|
||||
.build());
|
||||
} else {
|
||||
final boolean isVideoOnly = itag.itagType == ItagItem.ItagType.VIDEO_ONLY;
|
||||
final VideoStream videoStream = new VideoStream.Builder()
|
||||
.setId(String.valueOf(itag.id))
|
||||
.setContent(manualDashFromRepresentation(doc, representation),
|
||||
false)
|
||||
.setMediaFormat(mediaFormat)
|
||||
.setDeliveryMethod(DeliveryMethod.DASH)
|
||||
.setResolution(Objects.requireNonNull(itag.getResolutionString()))
|
||||
.setIsVideoOnly(isVideoOnly)
|
||||
.setBaseUrl(dashMpdUrl)
|
||||
.setItagItem(itag)
|
||||
.build();
|
||||
if (isVideoOnly) {
|
||||
videoOnlyStreams.add(videoStream);
|
||||
} else {
|
||||
videoStreams.add(videoStream);
|
||||
}
|
||||
}
|
||||
} catch (final Exception ignored) {
|
||||
}
|
||||
}
|
||||
return new Result(videoStreams, videoOnlyStreams, audioStreams);
|
||||
} catch (final Exception e) {
|
||||
throw new DashMpdParsingException("Could not parse DASH MPD", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private static String manualDashFromRepresentation(@Nonnull final Document document,
|
||||
@Nonnull final Element representation)
|
||||
throws TransformerException {
|
||||
final Element mpdElement = (Element) document.getElementsByTagName("MPD").item(0);
|
||||
|
||||
// Clone the element so we can freely modify it
|
||||
final Element adaptationSet = (Element) representation.getParentNode();
|
||||
final Element adaptationSetClone = (Element) adaptationSet.cloneNode(true);
|
||||
|
||||
// Remove other representations from the adaptation set
|
||||
final NodeList representations = adaptationSetClone.getElementsByTagName("Representation");
|
||||
for (int i = representations.getLength() - 1; i >= 0; i--) {
|
||||
final Node item = representations.item(i);
|
||||
if (!item.isEqualNode(representation)) {
|
||||
adaptationSetClone.removeChild(item);
|
||||
}
|
||||
}
|
||||
|
||||
final Element newMpdRootElement = (Element) mpdElement.cloneNode(false);
|
||||
final Element periodElement = newMpdRootElement.getOwnerDocument().createElement("Period");
|
||||
periodElement.appendChild(adaptationSetClone);
|
||||
newMpdRootElement.appendChild(periodElement);
|
||||
|
||||
return nodeToString(newMpdRootElement);
|
||||
}
|
||||
|
||||
private static String nodeToString(final Node node) throws TransformerException {
|
||||
final StringWriter result = new StringWriter();
|
||||
final Transformer transformer = TransformerFactory.newInstance().newTransformer();
|
||||
transformer.setOutputProperty(OutputKeys.VERSION, "1.0");
|
||||
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
|
||||
transformer.transform(new DOMSource(node), new StreamResult(result));
|
||||
return result.toString();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue