Skip to content

Commit b204560

Browse files
committed
Add dynamic itag support.
1 parent 5492343 commit b204560

File tree

2 files changed

+76
-13
lines changed

2 files changed

+76
-13
lines changed

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

Lines changed: 66 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@ public class ItagItem implements Serializable {
7979
new ItagItem(400, VIDEO_ONLY, MPEG_4, "1440p"),
8080
new ItagItem(266, VIDEO_ONLY, MPEG_4, "2160p"),
8181
new ItagItem(401, VIDEO_ONLY, MPEG_4, "2160p"),
82+
new ItagItem(402, VIDEO_ONLY, MPEG_4, "4320p"), // can be 4320p60 as well
83+
new ItagItem(571, VIDEO_ONLY, MPEG_4, "4320p"),
84+
// can be 4320p60 HDR as well (1La4QzGeaaQ)
85+
new ItagItem(402, VIDEO_ONLY, MPEG_4, "4320p60", 60),
8286

8387
new ItagItem(278, VIDEO_ONLY, WEBM, "144p"),
8488
new ItagItem(242, VIDEO_ONLY, WEBM, "240p"),
@@ -89,28 +93,19 @@ public class ItagItem implements Serializable {
8993
new ItagItem(247, VIDEO_ONLY, WEBM, "720p"),
9094
new ItagItem(248, VIDEO_ONLY, WEBM, "1080p"),
9195
new ItagItem(271, VIDEO_ONLY, WEBM, "1440p"),
92-
// #272 is either 3840x2160 (e.g. RtoitU2A-3E) or 7680x4320 (sLprVF6d7Ug)
93-
new ItagItem(272, VIDEO_ONLY, WEBM, "2160p"),
9496
new ItagItem(302, VIDEO_ONLY, WEBM, "720p60", 60),
9597
new ItagItem(303, VIDEO_ONLY, WEBM, "1080p60", 60),
9698
new ItagItem(308, VIDEO_ONLY, WEBM, "1440p60", 60),
9799
new ItagItem(313, VIDEO_ONLY, WEBM, "2160p"),
98-
new ItagItem(315, VIDEO_ONLY, WEBM, "2160p60", 60)
100+
new ItagItem(315, VIDEO_ONLY, WEBM, "2160p60", 60),
101+
new ItagItem(272, VIDEO_ONLY, WEBM, "4320p60", 60)
99102
};
100103

101104
/*//////////////////////////////////////////////////////////////////////////
102105
// Utils
103106
//////////////////////////////////////////////////////////////////////////*/
104107

105-
public static boolean isSupported(final int itag) {
106-
for (final ItagItem item : ITAG_LIST) {
107-
if (itag == item.id) {
108-
return true;
109-
}
110-
}
111-
return false;
112-
}
113-
108+
@Deprecated
114109
@Nonnull
115110
public static ItagItem getItag(final int itagId) throws ParsingException {
116111
for (final ItagItem item : ITAG_LIST) {
@@ -121,6 +116,65 @@ public static ItagItem getItag(final int itagId) throws ParsingException {
121116
throw new ParsingException("itag " + itagId + " is not supported");
122117
}
123118

119+
public static ItagItem getItag(final int itagId, final int averageBitrate,
120+
final int fps, final String qualityLabel, final String mimeType)
121+
throws ParsingException {
122+
123+
final String[] split = mimeType.split(";")[0].split("/");
124+
final String streamType = split[0];
125+
final String fileType = split[1];
126+
final String codec = mimeType.split("\"")[1];
127+
128+
MediaFormat format = null;
129+
ItagType itagType = null;
130+
131+
if (codec.contains(",")) { // muxed streams have both an audio and video codec
132+
itagType = VIDEO;
133+
} else {
134+
if (streamType.equals("video")) {
135+
itagType = VIDEO_ONLY;
136+
}
137+
if (streamType.equals("audio")) {
138+
itagType = AUDIO;
139+
}
140+
}
141+
142+
if (itagType == VIDEO) {
143+
if (fileType.equals("mp4")) {
144+
format = MPEG_4;
145+
}
146+
if (fileType.equals("3gpp")) {
147+
format = v3GPP;
148+
}
149+
}
150+
151+
if (itagType == VIDEO_ONLY) {
152+
if (fileType.equals("mp4")) {
153+
format = MPEG_4;
154+
}
155+
if (fileType.equals("webm")) {
156+
format = WEBM;
157+
}
158+
}
159+
160+
if (itagType == AUDIO) {
161+
if (fileType.equals("mp4") && (codec.startsWith("m4a") || codec.startsWith("mp4a"))) {
162+
format = M4A;
163+
}
164+
if (fileType.startsWith("webm") && codec.equals("opus")) {
165+
format = WEBMA_OPUS;
166+
}
167+
}
168+
169+
if (itagType == null || format == null) {
170+
throw new ParsingException("Unknown mimeType: " + mimeType);
171+
}
172+
173+
return itagType == AUDIO
174+
? new ItagItem(itagId, itagType, format, Math.round(averageBitrate / 1024f))
175+
: new ItagItem(itagId, itagType, format, qualityLabel, fps);
176+
}
177+
124178
/*//////////////////////////////////////////////////////////////////////////
125179
// Static constants
126180
//////////////////////////////////////////////////////////////////////////*/

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1412,9 +1412,18 @@ private java.util.stream.Stream<ItagInfo> getStreamsFromStreamingDataKey(
14121412
return streamingData.getArray(streamingDataKey).stream()
14131413
.filter(JsonObject.class::isInstance)
14141414
.map(JsonObject.class::cast)
1415+
.filter(formatData -> !formatData.getString("mimeType", "")
1416+
.startsWith("text"))
14151417
.map(formatData -> {
14161418
try {
1417-
final ItagItem itagItem = ItagItem.getItag(formatData.getInt("itag"));
1419+
final int itag = formatData.getInt("itag");
1420+
final int averageBitrate = formatData.getInt("averageBitrate");
1421+
final int fps = formatData.getInt("fps");
1422+
final String qualityLabel = formatData.getString("qualityLabel");
1423+
final String mimeType = formatData.getString("mimeType");
1424+
1425+
final ItagItem itagItem = ItagItem.
1426+
getItag(itag, averageBitrate, fps, qualityLabel, mimeType);
14181427
if (itagItem.itagType == itagTypeWanted) {
14191428
return buildAndAddItagInfoToList(videoId, formatData, itagItem,
14201429
itagItem.itagType, contentPlaybackNonce);

0 commit comments

Comments
 (0)