mirror of
https://github.com/TeamNewPipe/NewPipeExtractor.git
synced 2024-12-13 13:50:33 +05:30
add support for segmented streams
This commit is contained in:
parent
32d316330c
commit
4de99ae28f
@ -152,6 +152,9 @@ public class StreamInfo extends Info {
|
|||||||
streamInfo.getVideoOnlyStreams().addAll(result.getVideoOnlyStreams());
|
streamInfo.getVideoOnlyStreams().addAll(result.getVideoOnlyStreams());
|
||||||
streamInfo.getAudioStreams().addAll(result.getAudioStreams());
|
streamInfo.getAudioStreams().addAll(result.getAudioStreams());
|
||||||
streamInfo.getVideoStreams().addAll(result.getVideoStreams());
|
streamInfo.getVideoStreams().addAll(result.getVideoStreams());
|
||||||
|
streamInfo.segmentedVideoOnlyStreams = result.getSegmentedVideoOnlyStreams();
|
||||||
|
streamInfo.segmentedAudioStreams = result.getSegmentedAudioStreams();
|
||||||
|
streamInfo.segmentedVideoStreams = result.getSegmentedVideoStreams();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// Sometimes we receive 403 (forbidden) error when trying to download the manifest (similar to what happens with youtube-dl),
|
// Sometimes we receive 403 (forbidden) error when trying to download the manifest (similar to what happens with youtube-dl),
|
||||||
// just skip the exception (but store it somewhere), as we later check if we have streams anyway.
|
// just skip the exception (but store it somewhere), as we later check if we have streams anyway.
|
||||||
@ -271,6 +274,11 @@ public class StreamInfo extends Info {
|
|||||||
private List<VideoStream> videoOnlyStreams;
|
private List<VideoStream> videoOnlyStreams;
|
||||||
|
|
||||||
private String dashMpdUrl;
|
private String dashMpdUrl;
|
||||||
|
private List<VideoStream> segmentedVideoStreams;
|
||||||
|
private List<AudioStream> segmentedAudioStreams;
|
||||||
|
private List<VideoStream> segmentedVideoOnlyStreams;
|
||||||
|
|
||||||
|
|
||||||
private String hlsUrl;
|
private String hlsUrl;
|
||||||
private StreamInfoItem nextVideo;
|
private StreamInfoItem nextVideo;
|
||||||
private List<InfoItem> relatedStreams;
|
private List<InfoItem> relatedStreams;
|
||||||
@ -431,6 +439,30 @@ public class StreamInfo extends Info {
|
|||||||
this.dashMpdUrl = dashMpdUrl;
|
this.dashMpdUrl = dashMpdUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<VideoStream> getSegmentedVideoStreams() {
|
||||||
|
return segmentedVideoStreams;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSegmentedVideoStreams(List<VideoStream> segmentedVideoStreams) {
|
||||||
|
this.segmentedVideoStreams = segmentedVideoStreams;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<AudioStream> getSegmentedAudioStreams() {
|
||||||
|
return segmentedAudioStreams;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSegmentedAudioStreams(List<AudioStream> segmentedAudioStreams) {
|
||||||
|
this.segmentedAudioStreams = segmentedAudioStreams;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<VideoStream> getSegmentedVideoOnlyStreams() {
|
||||||
|
return segmentedVideoOnlyStreams;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSegmentedVideoOnlyStreams(List<VideoStream> segmentedVideoOnlyStreams) {
|
||||||
|
this.segmentedVideoOnlyStreams = segmentedVideoOnlyStreams;
|
||||||
|
}
|
||||||
|
|
||||||
public String getHlsUrl() {
|
public String getHlsUrl() {
|
||||||
return hlsUrl;
|
return hlsUrl;
|
||||||
}
|
}
|
||||||
|
@ -59,10 +59,23 @@ public class DashMpdParser {
|
|||||||
private final List<AudioStream> audioStreams;
|
private final List<AudioStream> audioStreams;
|
||||||
private final List<VideoStream> videoOnlyStreams;
|
private final List<VideoStream> videoOnlyStreams;
|
||||||
|
|
||||||
public ParserResult(List<VideoStream> videoStreams, List<AudioStream> audioStreams, List<VideoStream> videoOnlyStreams) {
|
private final List<VideoStream> segmentedVideoStreams;
|
||||||
|
private final List<AudioStream> segmentedAudioStreams;
|
||||||
|
private final List<VideoStream> segmentedVideoOnlyStreams;
|
||||||
|
|
||||||
|
|
||||||
|
public ParserResult(List<VideoStream> videoStreams,
|
||||||
|
List<AudioStream> audioStreams,
|
||||||
|
List<VideoStream> videoOnlyStreams,
|
||||||
|
List<VideoStream> segmentedVideoStreams,
|
||||||
|
List<AudioStream> segmentedAudioStreams,
|
||||||
|
List<VideoStream> segmentedVideoOnlyStreams) {
|
||||||
this.videoStreams = videoStreams;
|
this.videoStreams = videoStreams;
|
||||||
this.audioStreams = audioStreams;
|
this.audioStreams = audioStreams;
|
||||||
this.videoOnlyStreams = videoOnlyStreams;
|
this.videoOnlyStreams = videoOnlyStreams;
|
||||||
|
this.segmentedVideoStreams = segmentedVideoStreams;
|
||||||
|
this.segmentedAudioStreams = segmentedAudioStreams;
|
||||||
|
this.segmentedVideoOnlyStreams = segmentedVideoOnlyStreams;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<VideoStream> getVideoStreams() {
|
public List<VideoStream> getVideoStreams() {
|
||||||
@ -76,10 +89,22 @@ public class DashMpdParser {
|
|||||||
public List<VideoStream> getVideoOnlyStreams() {
|
public List<VideoStream> getVideoOnlyStreams() {
|
||||||
return videoOnlyStreams;
|
return videoOnlyStreams;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<VideoStream> getSegmentedVideoStreams() {
|
||||||
|
return segmentedVideoStreams;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<AudioStream> getSegmentedAudioStreams() {
|
||||||
|
return segmentedAudioStreams;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<VideoStream> getSegmentedVideoOnlyStreams() {
|
||||||
|
return segmentedVideoOnlyStreams;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Will try to download (using {@link StreamInfo#dashMpdUrl}) and parse the dash manifest,
|
* Will try to download (using {@link StreamInfo#getDashMpdUrl()}) and parse the dash manifest,
|
||||||
* then it will search for any stream that the ItagItem has (by the id).
|
* then it will search for any stream that the ItagItem has (by the id).
|
||||||
* <p>
|
* <p>
|
||||||
* It has video, video only and audio streams and will only add to the list if it don't
|
* It has video, video only and audio streams and will only add to the list if it don't
|
||||||
@ -90,7 +115,8 @@ public class DashMpdParser {
|
|||||||
*
|
*
|
||||||
* @param streamInfo where the parsed streams will be added
|
* @param streamInfo where the parsed streams will be added
|
||||||
*/
|
*/
|
||||||
public static ParserResult getStreams(final StreamInfo streamInfo) throws DashMpdParsingException, ReCaptchaException {
|
public static ParserResult getStreams(final StreamInfo streamInfo)
|
||||||
|
throws DashMpdParsingException, ReCaptchaException {
|
||||||
String dashDoc;
|
String dashDoc;
|
||||||
Downloader downloader = NewPipe.getDownloader();
|
Downloader downloader = NewPipe.getDownloader();
|
||||||
try {
|
try {
|
||||||
@ -113,6 +139,10 @@ public class DashMpdParser {
|
|||||||
final List<AudioStream> audioStreams = new ArrayList<>();
|
final List<AudioStream> audioStreams = new ArrayList<>();
|
||||||
final List<VideoStream> videoOnlyStreams = new ArrayList<>();
|
final List<VideoStream> videoOnlyStreams = new ArrayList<>();
|
||||||
|
|
||||||
|
final List<VideoStream> segmentedVideoStreams = new ArrayList<>();
|
||||||
|
final List<AudioStream> segmentedAudioStreams = new ArrayList<>();
|
||||||
|
final List<VideoStream> segmentedVideoOnlyStreams = new ArrayList<>();
|
||||||
|
|
||||||
for (int i = 0; i < representationList.getLength(); i++) {
|
for (int i = 0; i < representationList.getLength(); i++) {
|
||||||
final Element representation = (Element) representationList.item(i);
|
final Element representation = (Element) representationList.item(i);
|
||||||
try {
|
try {
|
||||||
@ -126,34 +156,61 @@ public class DashMpdParser {
|
|||||||
// instead we need to add the "media=" value from the <SegementURL/> tags inside the <SegmentList/>
|
// instead we need to add the "media=" value from the <SegementURL/> tags inside the <SegmentList/>
|
||||||
// tag in order to get a full working url. However each of these is just pointing to a part of the
|
// tag in order to get a full working url. However each of these is just pointing to a part of the
|
||||||
// video, so we can not return a URL with a working stream here.
|
// video, so we can not return a URL with a working stream here.
|
||||||
// We decided not to ignore such streams for the moment.
|
// Instead of putting those streams into the list of regular stream urls wie put them in a
|
||||||
if (itag != null && segmentationList == null) {
|
// for example "segmentedVideoStreams" list.
|
||||||
|
if (itag != null) {
|
||||||
final MediaFormat mediaFormat = MediaFormat.getFromMimeType(mimeType);
|
final MediaFormat mediaFormat = MediaFormat.getFromMimeType(mimeType);
|
||||||
|
|
||||||
if (itag.itagType.equals(ItagItem.ItagType.AUDIO)) {
|
if (itag.itagType.equals(ItagItem.ItagType.AUDIO)) {
|
||||||
final AudioStream audioStream = new AudioStream(url, mediaFormat, itag.avgBitrate);
|
if(segmentationList == null) {
|
||||||
|
final AudioStream audioStream = new AudioStream(url, mediaFormat, itag.avgBitrate);
|
||||||
if (!Stream.containSimilarStream(audioStream, streamInfo.getAudioStreams())) {
|
if (!Stream.containSimilarStream(audioStream, streamInfo.getAudioStreams())) {
|
||||||
audioStreams.add(audioStream);
|
audioStreams.add(audioStream);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
segmentedAudioStreams.add(
|
||||||
|
new AudioStream(id, mediaFormat, itag.avgBitrate));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
boolean isVideoOnly = itag.itagType.equals(ItagItem.ItagType.VIDEO_ONLY);
|
boolean isVideoOnly = itag.itagType.equals(ItagItem.ItagType.VIDEO_ONLY);
|
||||||
final VideoStream videoStream = new VideoStream(url, mediaFormat, itag.resolutionString, isVideoOnly);
|
|
||||||
|
|
||||||
if (isVideoOnly) {
|
if(segmentationList == null) {
|
||||||
if (!Stream.containSimilarStream(videoStream, streamInfo.getVideoOnlyStreams())) {
|
final VideoStream videoStream = new VideoStream(url,
|
||||||
streamInfo.getVideoOnlyStreams().add(videoStream);
|
mediaFormat,
|
||||||
videoOnlyStreams.add(videoStream);
|
itag.resolutionString,
|
||||||
|
isVideoOnly);
|
||||||
|
|
||||||
|
if (isVideoOnly) {
|
||||||
|
if (!Stream.containSimilarStream(videoStream, streamInfo.getVideoOnlyStreams())) {
|
||||||
|
videoOnlyStreams.add(videoStream);
|
||||||
|
}
|
||||||
|
} else if (!Stream.containSimilarStream(videoStream, streamInfo.getVideoStreams())) {
|
||||||
|
videoStreams.add(videoStream);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
final VideoStream videoStream = new VideoStream(id,
|
||||||
|
mediaFormat,
|
||||||
|
itag.resolutionString,
|
||||||
|
isVideoOnly);
|
||||||
|
|
||||||
|
if(isVideoOnly) {
|
||||||
|
segmentedVideoOnlyStreams.add(videoStream);
|
||||||
|
} else {
|
||||||
|
segmentedVideoStreams.add(videoStream);
|
||||||
}
|
}
|
||||||
} else if (!Stream.containSimilarStream(videoStream, streamInfo.getVideoStreams())) {
|
|
||||||
videoStreams.add(videoStream);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception ignored) {
|
} catch (Exception ignored) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new ParserResult(videoStreams, audioStreams, videoOnlyStreams);
|
return new ParserResult(
|
||||||
|
videoStreams,
|
||||||
|
audioStreams,
|
||||||
|
videoOnlyStreams,
|
||||||
|
segmentedVideoStreams,
|
||||||
|
segmentedAudioStreams,
|
||||||
|
segmentedVideoOnlyStreams);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new DashMpdParsingException("Could not parse Dash mpd", e);
|
throw new DashMpdParsingException("Could not parse Dash mpd", e);
|
||||||
}
|
}
|
||||||
|
@ -47,15 +47,21 @@ public class YoutubeStreamExtractorDASHTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetDashMpd() {
|
public void testGetDashMpd() {
|
||||||
System.out.println(info.getDashMpdUrl());
|
|
||||||
assertTrue(info.getDashMpdUrl(),
|
assertTrue(info.getDashMpdUrl(),
|
||||||
info.getDashMpdUrl() != null && !info.getDashMpdUrl().isEmpty());
|
info.getDashMpdUrl() != null && !info.getDashMpdUrl().isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDashMpdParser() {
|
public void testRegularStreams() {
|
||||||
assertEquals(0, info.getAudioStreams().size());
|
assertEquals(0, info.getAudioStreams().size());
|
||||||
assertEquals(0, info.getVideoOnlyStreams().size());
|
assertEquals(0, info.getVideoOnlyStreams().size());
|
||||||
assertEquals(4, info.getVideoStreams().size());
|
assertEquals(4, info.getVideoStreams().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSegmentedStreams() {
|
||||||
|
assertEquals(2, info.getSegmentedAudioStreams().size());
|
||||||
|
assertEquals(3, info.getSegmentedVideoOnlyStreams().size());
|
||||||
|
assertEquals(0, info.getSegmentedVideoStreams().size());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ public class YoutubeSearchCountTest {
|
|||||||
public void testViewCount() {
|
public void testViewCount() {
|
||||||
ChannelInfoItem ci = (ChannelInfoItem) itemsPage.getItems().get(0);
|
ChannelInfoItem ci = (ChannelInfoItem) itemsPage.getItems().get(0);
|
||||||
assertTrue("Count does not fit: " + Long.toString(ci.getSubscriberCount()),
|
assertTrue("Count does not fit: " + Long.toString(ci.getSubscriberCount()),
|
||||||
65043316 < ci.getSubscriberCount() && ci.getSubscriberCount() < 68043316);
|
69043316 < ci.getSubscriberCount() && ci.getSubscriberCount() < 73043316);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user