Skip to content

Commit ec6b99c

Browse files
committed
[Youtube] Adjust mix extractor to new user agent
Also extract continuation now
1 parent 0ff054a commit ec6b99c

1 file changed

Lines changed: 43 additions & 97 deletions

File tree

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

Lines changed: 43 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.schabi.newpipe.extractor.services.youtube.extractors;
22

3+
import static org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeParsingHelper.fixThumbnailUrl;
34
import static org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeParsingHelper.getJsonResponse;
45

56
import com.grack.nanojson.JsonArray;
@@ -29,7 +30,7 @@
2930
public class YoutubeMixPlaylistExtractor extends PlaylistExtractor {
3031

3132
private JsonObject initialData;
32-
private Document doc;
33+
private JsonObject playlistData;
3334

3435
public YoutubeMixPlaylistExtractor(StreamingService service, ListLinkHandler linkHandler) {
3536
super(service, linkHandler);
@@ -40,18 +41,17 @@ public void onFetchPage(@Nonnull Downloader downloader) throws IOException, Extr
4041
final String url = getUrl() + "&pbj=1";
4142
final JsonArray ajaxJson = getJsonResponse(url, getExtractorLocalization());
4243
initialData = ajaxJson.getObject(3).getObject("response");
43-
JsonObject a = initialData.getObject("contents");
44-
JsonObject b = initialData.getObject("contents").getObject("twoColumnWatchNextResults");
45-
JsonObject c = initialData.getObject("contents");
46-
JsonObject playlist = initialData.getObject("contents").getObject("twoColumnWatchNextResults").getObject("playlist").getObject("playlist");
44+
playlistData = initialData.getObject("contents").getObject("twoColumnWatchNextResults").getObject("playlist").getObject("playlist");
4745
System.out.println();
4846
}
4947

5048
@Nonnull
5149
@Override
5250
public String getName() throws ParsingException {
5351
try {
54-
return doc.select("div[class=\"playlist-info\"] h3[class=\"playlist-title\"]").first().text();
52+
final String name = playlistData.getString("title");
53+
if (name!= null) return name;
54+
else return "";
5555
} catch (Exception e) {
5656
throw new ParsingException("Could not get playlist name", e);
5757
}
@@ -60,16 +60,8 @@ public String getName() throws ParsingException {
6060
@Override
6161
public String getThumbnailUrl() throws ParsingException {
6262
try {
63-
Element li = doc.select("ol[class*=\"playlist-videos-list\"] li").first();
64-
String videoId = li.attr("data-video-id");
65-
if (videoId != null && !videoId.isEmpty()) {
66-
//higher quality
67-
return getThumbnailUrlFromId(videoId);
68-
} else {
69-
//lower quality
70-
return doc.select("ol[class*=\"playlist-videos-list\"] li").first()
71-
.attr("data-thumbnail-url");
72-
}
63+
final String videoId = playlistData.getArray("contents").getObject(0).getString("videoId");
64+
return getThumbnailUrlFromId(videoId);
7365
} catch (Exception e) {
7466
throw new ParsingException("Could not get playlist thumbnail", e);
7567
}
@@ -101,112 +93,66 @@ public String getUploaderAvatarUrl() {
10193
@Override
10294
public long getStreamCount() {
10395
// Auto-generated playlist always start with 25 videos and are endless
104-
// But the html doesn't have a continuation url
105-
return doc.select("ol[class*=\"playlist-videos-list\"] li").size();
96+
return 25;
10697
}
10798

10899
@Nonnull
109100
@Override
110101
public InfoItemsPage<StreamInfoItem> getInitialPage() {
111102
StreamInfoItemsCollector collector = new StreamInfoItemsCollector(getServiceId());
112-
Element ol = doc.select("ol[class*=\"playlist-videos-list\"]").first();
113-
collectStreamsFrom(collector, ol);
103+
collectStreamsFrom(collector, playlistData.getArray("contents"));
114104
return new InfoItemsPage<>(collector, getNextPageUrl());
115105
}
116106

117107
@Override
118108
public String getNextPageUrl() {
119-
return "";
109+
final JsonObject lastStream = ((JsonObject) playlistData.getArray("contents")
110+
.get(playlistData.getArray("contents").size() - 1));
111+
final String lastStreamId = lastStream.getObject("playlistPanelVideoRenderer")
112+
.getString("videoId");
113+
return "https://youtube.com" + lastStream.getObject("playlistPanelVideoRenderer").getObject("navigationEndpoint")
114+
.getObject("commandMetadata").getObject("webCommandMetadata").getString("url") + "&pbj=1";
120115
}
121116

122117
@Override
123-
public InfoItemsPage<StreamInfoItem> getPage(final String pageUrl) {
124-
//Continuations are not implemented
125-
return null;
118+
public InfoItemsPage<StreamInfoItem> getPage(final String pageUrl)
119+
throws ExtractionException, IOException {
120+
if (pageUrl == null || pageUrl.isEmpty()) {
121+
throw new ExtractionException(new IllegalArgumentException("Page url is empty or null"));
122+
}
123+
124+
StreamInfoItemsCollector collector = new StreamInfoItemsCollector(getServiceId());
125+
final JsonArray ajaxJson = getJsonResponse(pageUrl, getExtractorLocalization());
126+
playlistData =
127+
ajaxJson.getObject(3).getObject("response").getObject("contents")
128+
.getObject("twoColumnWatchNextResults").getObject("playlist")
129+
.getObject("playlist");
130+
final JsonArray streams = playlistData.getArray("contents");
131+
//Because continuation requests are created with the last video of previous request as start
132+
streams.remove(0);
133+
collectStreamsFrom(collector, streams);
134+
return new InfoItemsPage<>(collector, getNextPageUrl());
126135
}
127136

128137
private void collectStreamsFrom(
129138
@Nonnull StreamInfoItemsCollector collector,
130-
@Nullable Element element) {
139+
@Nullable JsonArray streams) {
131140
collector.reset();
132141

133-
if (element == null) {
142+
if (streams == null) {
134143
return;
135144
}
136145

137-
final LinkHandlerFactory streamLinkHandlerFactory = getService().getStreamLHFactory();
138146
final TimeAgoParser timeAgoParser = getTimeAgoParser();
139147

140-
// for (final Element li : element.children()) {
141-
//
142-
// collector.commit(new YoutubeStreamInfoItemExtractor(li, timeAgoParser) {
143-
//
144-
// @Override
145-
// public boolean isAd() {
146-
// return false;
147-
// }
148-
//
149-
// @Override
150-
// public String getUrl() throws ParsingException {
151-
// try {
152-
// return streamLinkHandlerFactory.fromId(li.attr("data-video-id")).getUrl();
153-
// } catch (Exception e) {
154-
// throw new ParsingException("Could not get web page url for the video", e);
155-
// }
156-
// }
157-
//
158-
// @Override
159-
// public String getName() throws ParsingException {
160-
// try {
161-
// return li.attr("data-video-title");
162-
// } catch (Exception e) {
163-
// throw new ParsingException("Could not get name", e);
164-
// }
165-
// }
166-
//
167-
// @Override
168-
// public long getDuration() {
169-
// //Not present in doc
170-
// return 0;
171-
// }
172-
//
173-
// @Override
174-
// public String getUploaderName() throws ParsingException {
175-
// String uploaderName = li.attr("data-video-username");
176-
// if (uploaderName == null || uploaderName.isEmpty()) {
177-
// throw new ParsingException("Could not get uploader name");
178-
// } else {
179-
// return uploaderName;
180-
// }
181-
// }
182-
//
183-
// @Override
184-
// public String getUploaderUrl() {
185-
// //Not present in doc
186-
// return "";
187-
// }
188-
//
189-
// @Override
190-
// public String getTextualUploadDate() {
191-
// //Not present in doc
192-
// return "";
193-
// }
194-
//
195-
// @Override
196-
// public long getViewCount() {
197-
// return -1;
198-
// }
199-
//
200-
// @Override
201-
// public String getThumbnailUrl() throws ParsingException {
202-
// try {
203-
// return getThumbnailUrlFromId(streamLinkHandlerFactory.fromUrl(getUrl()).getId());
204-
// } catch (Exception e) {
205-
// throw new ParsingException("Could not get thumbnail url", e);
206-
// }
207-
// }
208-
// });
209-
// }
148+
for (Object stream : streams) {
149+
if (stream instanceof JsonObject) {
150+
JsonObject streamInfo = ((JsonObject) stream).getObject("playlistPanelVideoRenderer");
151+
if (streamInfo != null) {
152+
collector.commit(new YoutubeStreamInfoItemExtractor(streamInfo, timeAgoParser));
153+
}
154+
}
155+
}
210156
}
211157

212158
private String getThumbnailUrlFromId(String videoId) {

0 commit comments

Comments
 (0)