Skip to content

Commit 7f19059

Browse files
committed
[YouTube] Don't generate manifests for post live streams when loading the stream info
Like for OTF streams, to prevent errors, unused requests, and improve the content loading. Add getters and setter for ItagInfo objects. Fields of this class are now private. Add some unknown constants and some JavaDocs
1 parent aca7a3e commit 7f19059

4 files changed

Lines changed: 128 additions & 62 deletions

File tree

extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/ItagInfo.java

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,29 @@
33
import java.io.Serializable;
44

55
public class ItagInfo implements Serializable {
6-
public String content;
7-
public ItagItem itagItem;
8-
public boolean isUrl;
6+
private final String content;
7+
private final ItagItem itagItem;
8+
private boolean isUrl;
99

1010
public ItagInfo(final String content,
11-
final ItagItem itagItem,
12-
final boolean isUrl) {
11+
final ItagItem itagItem) {
1312
this.content = content;
1413
this.itagItem = itagItem;
14+
}
15+
16+
public void setIsUrl(final boolean isUrl) {
1517
this.isUrl = isUrl;
1618
}
19+
20+
public String getContent() {
21+
return content;
22+
}
23+
24+
public ItagItem getItagItem() {
25+
return itagItem;
26+
}
27+
28+
public boolean getIsUrl() {
29+
return isUrl;
30+
}
1731
}

extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/ItagItem.java

Lines changed: 86 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ public class ItagItem implements Serializable {
1717
*/
1818
private static final ItagItem[] ITAG_LIST = {
1919
/////////////////////////////////////////////////////
20-
// VIDEO ID Type Format Resolution FPS ///
21-
///////////////////////////////////////////////////
20+
// VIDEO ID Type Format Resolution FPS ////
21+
/////////////////////////////////////////////////////
2222
new ItagItem(17, VIDEO, v3GPP, "144p"),
2323
new ItagItem(36, VIDEO, v3GPP, "240p"),
2424

@@ -36,8 +36,8 @@ public class ItagItem implements Serializable {
3636
new ItagItem(45, VIDEO, WEBM, "720p"),
3737
new ItagItem(46, VIDEO, WEBM, "1080p"),
3838

39-
////////////////////////////////////////////////////////////////////
40-
// AUDIO ID ItagType Format Bitrate ///
39+
//////////////////////////////////////////////////////////////////
40+
// AUDIO ID ItagType Format Bitrate //
4141
//////////////////////////////////////////////////////////////////
4242
new ItagItem(171, AUDIO, WEBMA, 128),
4343
new ItagItem(172, AUDIO, WEBMA, 256),
@@ -49,8 +49,8 @@ public class ItagItem implements Serializable {
4949
new ItagItem(251, AUDIO, WEBMA_OPUS, 160),
5050

5151
/// VIDEO ONLY ////////////////////////////////////////////
52-
// ID Type Format Resolution FPS ///
53-
/////////////////////////////////////////////////////////
52+
// ID Type Format Resolution FPS ////
53+
///////////////////////////////////////////////////////////
5454
new ItagItem(160, VIDEO_ONLY, MPEG_4, "144p"),
5555
new ItagItem(133, VIDEO_ONLY, MPEG_4, "240p"),
5656
new ItagItem(134, VIDEO_ONLY, MPEG_4, "360p"),
@@ -100,11 +100,20 @@ public static ItagItem getItag(final int itagId) throws ParsingException {
100100
return item;
101101
}
102102
}
103-
throw new ParsingException("itag=" + itagId + " not supported");
103+
throw new ParsingException("itag " + itagId + " is not supported");
104104
}
105105

106106
/*//////////////////////////////////////////////////////////////////////////
107-
// Contructors and misc
107+
// Static constants
108+
//////////////////////////////////////////////////////////////////////////*/
109+
110+
public static final int AVERAGE_BITRATE_UNKNOWN = -1;
111+
public static final int SAMPLE_RATE_UNKNOWN = -1;
112+
public static final int FPS_UNKNOWN = -1;
113+
public static final int TARGET_DURATION_SEC_UNKNOWN = -1;
114+
115+
/*//////////////////////////////////////////////////////////////////////////
116+
// Constructors and misc
108117
//////////////////////////////////////////////////////////////////////////*/
109118

110119
public enum ItagType {
@@ -163,12 +172,12 @@ public MediaFormat getMediaFormat() {
163172
public final ItagType itagType;
164173

165174
// Audio fields
166-
public int avgBitrate = -1;
167-
public int sampleRate = -1;
175+
public int avgBitrate = AVERAGE_BITRATE_UNKNOWN;
176+
private int sampleRate = SAMPLE_RATE_UNKNOWN;
168177

169178
// Video fields
170179
public String resolutionString;
171-
public int fps = -1;
180+
public int fps = FPS_UNKNOWN;
172181

173182
// Fields for Dash
174183
private int bitrate;
@@ -180,76 +189,133 @@ public MediaFormat getMediaFormat() {
180189
private int indexEnd;
181190
private String quality;
182191
private String codec;
192+
private int targetDurationSec = TARGET_DURATION_SEC_UNKNOWN;
183193

184194
public int getBitrate() {
185195
return bitrate;
186196
}
187197

188-
public void setBitrate(int bitrate) {
198+
public void setBitrate(final int bitrate) {
189199
this.bitrate = bitrate;
190200
}
191201

192202
public int getWidth() {
193203
return width;
194204
}
195205

196-
public void setWidth(int width) {
206+
public void setWidth(final int width) {
197207
this.width = width;
198208
}
199209

200210
public int getHeight() {
201211
return height;
202212
}
203213

204-
public void setHeight(int height) {
214+
public void setHeight(final int height) {
205215
this.height = height;
206216
}
207217

208218
public int getInitStart() {
209219
return initStart;
210220
}
211221

212-
public void setInitStart(int initStart) {
222+
public void setInitStart(final int initStart) {
213223
this.initStart = initStart;
214224
}
215225

216226
public int getInitEnd() {
217227
return initEnd;
218228
}
219229

220-
public void setInitEnd(int initEnd) {
230+
public void setInitEnd(final int initEnd) {
221231
this.initEnd = initEnd;
222232
}
223233

224234
public int getIndexStart() {
225235
return indexStart;
226236
}
227237

228-
public void setIndexStart(int indexStart) {
238+
public void setIndexStart(final int indexStart) {
229239
this.indexStart = indexStart;
230240
}
231241

232242
public int getIndexEnd() {
233243
return indexEnd;
234244
}
235245

236-
public void setIndexEnd(int indexEnd) {
246+
public void setIndexEnd(final int indexEnd) {
237247
this.indexEnd = indexEnd;
238248
}
239249

240250
public String getQuality() {
241251
return quality;
242252
}
243253

244-
public void setQuality(String quality) {
254+
public void setQuality(final String quality) {
245255
this.quality = quality;
246256
}
247257

248258
public String getCodec() {
249259
return codec;
250260
}
251261

252-
public void setCodec(String codec) {
262+
public void setCodec(final String codec) {
253263
this.codec = codec;
254264
}
265+
266+
/**
267+
* Get the {@code targetDurationSec} value.
268+
* <p>
269+
* This value is an average time in seconds of sequences duration of livestreams and ended
270+
* livestreams. It is only returned for these stream types by YouTube and makes no sense for
271+
* videos, so {@link #TARGET_DURATION_SEC_UNKNOWN} is returned for video streams.
272+
* </p>
273+
*
274+
* @return the targetDurationSec value or {@link #TARGET_DURATION_SEC_UNKNOWN}
275+
*/
276+
public int getTargetDurationSec() {
277+
return targetDurationSec;
278+
}
279+
280+
/**
281+
* Set the {@code targetDurationSec} value.
282+
* <p>
283+
* This value is an average time in seconds of sequences duration of livestreams and ended
284+
* livestreams. It is only returned for these stream types by YouTube and makes no sense for
285+
* videos, so {@link #TARGET_DURATION_SEC_UNKNOWN} will be set for video streams or if this
286+
* value is less than or equal to 0.
287+
* </p>
288+
*
289+
*/
290+
public void setTargetDurationSec(final int targetDurationSec) {
291+
if (targetDurationSec > 0) {
292+
this.targetDurationSec = targetDurationSec;
293+
}
294+
}
295+
296+
/**
297+
* Get the sample rate.
298+
* <p>
299+
* It is only known for audio streams, so {@link #SAMPLE_RATE_UNKNOWN} is returned for video
300+
* streams or if the sample rate is unknown.
301+
* </p>
302+
*
303+
* @return the sample rate or {@link #SAMPLE_RATE_UNKNOWN}
304+
*/
305+
public int getSampleRate() {
306+
return sampleRate;
307+
}
308+
309+
/**
310+
* Set the sample rate.
311+
* <p>
312+
* It is only known for audio streams, so {@link #SAMPLE_RATE_UNKNOWN} is set for video
313+
* streams or if the sample rate value is less than or equal to 0.
314+
* </p>
315+
*/
316+
public void setSampleRate(final int sampleRate) {
317+
if (sampleRate > 0) {
318+
this.sampleRate = sampleRate;
319+
}
320+
}
255321
}

extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeDashManifestCreator.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -478,10 +478,10 @@ private static void generateRepresentationElement(@Nonnull final Document docume
478478
representationElement.setAttributeNode(frameRateAttribute);
479479
}
480480

481-
if (itagType == ItagItem.ItagType.AUDIO && itagItem.sampleRate > 0) {
481+
if (itagType == ItagItem.ItagType.AUDIO && itagItem.getSampleRate() > 0) {
482482
final Attr audioSamplingRateAttribute = document.createAttribute(
483483
"audioSamplingRate");
484-
audioSamplingRateAttribute.setValue(String.valueOf(itagItem.sampleRate));
484+
audioSamplingRateAttribute.setValue(String.valueOf(itagItem.getSampleRate()));
485485
}
486486

487487
adaptationSetElement.appendChild(representationElement);

extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeStreamExtractor.java

Lines changed: 21 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -515,9 +515,9 @@ public List<AudioStream> getAudioStreams() throws ExtractionException {
515515
try {
516516
for (final ItagInfo itagInfo : getItags(ADAPTIVE_FORMATS,
517517
ItagItem.ItagType.AUDIO)) {
518-
final ItagItem itag = itagInfo.itagItem;
519-
final String content = itagInfo.content;
520-
final boolean isUrl = itagInfo.isUrl;
518+
final ItagItem itag = itagInfo.getItagItem();
519+
final String content = itagInfo.getContent();
520+
final boolean isUrl = itagInfo.getIsUrl();
521521
final AudioStream audioStream;
522522

523523
if (streamType == StreamType.VIDEO_STREAM) {
@@ -560,9 +560,9 @@ public List<VideoStream> getVideoStreams() throws ExtractionException {
560560

561561
try {
562562
for (final ItagInfo itagInfo : getItags(FORMATS, ItagItem.ItagType.VIDEO)) {
563-
final ItagItem itag = itagInfo.itagItem;
564-
final String content = itagInfo.content;
565-
final boolean isUrl = itagInfo.isUrl;
563+
final ItagItem itag = itagInfo.getItagItem();
564+
final String content = itagInfo.getContent();
565+
final boolean isUrl = itagInfo.getIsUrl();
566566
final VideoStream videoStream;
567567

568568
if (streamType == StreamType.VIDEO_STREAM) {
@@ -605,9 +605,9 @@ public List<VideoStream> getVideoOnlyStreams() throws ExtractionException {
605605
try {
606606
for (final ItagInfo itagInfo : getItags(ADAPTIVE_FORMATS,
607607
ItagItem.ItagType.VIDEO_ONLY)) {
608-
final ItagItem itag = itagInfo.itagItem;
609-
final String content = itagInfo.content;
610-
final boolean isUrl = itagInfo.isUrl;
608+
final ItagItem itag = itagInfo.getItagItem();
609+
final String content = itagInfo.getContent();
610+
final boolean isUrl = itagInfo.getIsUrl();
611611
final VideoStream videoOnlyStream;
612612

613613
if (streamType == StreamType.VIDEO_STREAM) {
@@ -1243,45 +1243,31 @@ private List<ItagInfo> getStreamsFromStreamingDataKey(
12431243
"-1")));
12441244
itagItem.setQuality(formatData.getString("quality"));
12451245
itagItem.setCodec(codec);
1246+
itagItem.setTargetDurationSec(formatData.getInt("targetDurationSec"));
12461247

12471248
if (itagType == ItagItem.ItagType.VIDEO
12481249
|| itagType == ItagItem.ItagType.VIDEO_ONLY) {
12491250
itagItem.fps = formatData.getInt("fps");
12501251
}
12511252
if (itagType == ItagItem.ItagType.AUDIO) {
1252-
itagItem.sampleRate = Integer.parseInt(formatData.getString(
1253-
"audioSampleRate"));
1253+
itagItem.setSampleRate(Integer.parseInt(formatData.getString(
1254+
"audioSampleRate")));
12541255
}
1256+
final ItagInfo itagInfo = new ItagInfo(streamUrl, itagItem);
12551257

12561258
if (streamType == StreamType.VIDEO_STREAM) {
1257-
if (formatData.getString("type", EMPTY_STRING)
1258-
.equalsIgnoreCase("FORMAT_STREAM_TYPE_OTF")) {
1259-
itagInfos.add(new ItagInfo(streamUrl, itagItem, false));
1260-
} else {
1261-
itagInfos.add(new ItagInfo(streamUrl, itagItem, true));
1262-
}
1263-
} else if (streamType == StreamType.POST_LIVE_STREAM) {
1264-
// Even if it increases the content loading, we need to generate
1265-
// manifests of post live streams now because the
1266-
// targetDurationSec value is required to create these manifests
1267-
try {
1268-
final String content =
1269-
createDashManifestFromPostLiveStreamDvrStreamingUrl(
1270-
streamUrl, itagItem, formatData
1271-
.getInt("targetDurationSec"));
1272-
itagInfos.add(new ItagInfo(content, itagItem, false));
1273-
} catch (final YoutubeDashManifestCreator
1274-
.YoutubeDashManifestCreationException ignored) {
1275-
// Something went wrong when generating the DASH manifest
1276-
// of the stream, don't add this stream to the stream list
1277-
}
1259+
itagInfo.setIsUrl(!formatData.getString("type", EMPTY_STRING)
1260+
.equalsIgnoreCase("FORMAT_STREAM_TYPE_OTF"));
12781261
} else {
12791262
// We are currently not able to generate DASH manifests for running
12801263
// livestreams, so because of the requirements of StreamInfo
1281-
// objects, return these streams as DASH streams
1282-
// (even if they are not playable).
1283-
itagInfos.add(new ItagInfo(streamUrl, itagItem, true));
1264+
// objects, return these streams as DASH URL streams (even if they
1265+
// are not playable).
1266+
// Ended livestreams are returned as non URL streams
1267+
itagInfo.setIsUrl(streamType != StreamType.POST_LIVE_STREAM);
12841268
}
1269+
1270+
itagInfos.add(itagInfo);
12851271
}
12861272
} catch (final UnsupportedEncodingException | ParsingException ignored) {
12871273
}

0 commit comments

Comments
 (0)