Fix first playlist page
This commit is contained in:
parent
4e57e589ce
commit
316fe0109d
|
@ -13,15 +13,12 @@ import org.schabi.newpipe.extractor.downloader.Downloader;
|
||||||
import org.schabi.newpipe.extractor.downloader.Response;
|
import org.schabi.newpipe.extractor.downloader.Response;
|
||||||
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||||
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
||||||
import org.schabi.newpipe.extractor.linkhandler.LinkHandlerFactory;
|
|
||||||
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
|
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
|
||||||
import org.schabi.newpipe.extractor.localization.TimeAgoParser;
|
import org.schabi.newpipe.extractor.localization.TimeAgoParser;
|
||||||
import org.schabi.newpipe.extractor.playlist.PlaylistExtractor;
|
import org.schabi.newpipe.extractor.playlist.PlaylistExtractor;
|
||||||
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeParsingHelper;
|
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeParsingHelper;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfoItemsCollector;
|
import org.schabi.newpipe.extractor.stream.StreamInfoItemsCollector;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamType;
|
|
||||||
import org.schabi.newpipe.extractor.utils.Parser;
|
|
||||||
import org.schabi.newpipe.extractor.utils.Utils;
|
import org.schabi.newpipe.extractor.utils.Utils;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -233,112 +230,23 @@ public class YoutubePlaylistExtractor extends PlaylistExtractor {
|
||||||
private void collectStreamsFrom(@Nonnull StreamInfoItemsCollector collector, @Nullable Element element) {
|
private void collectStreamsFrom(@Nonnull StreamInfoItemsCollector collector, @Nullable Element element) {
|
||||||
collector.reset();
|
collector.reset();
|
||||||
|
|
||||||
if (element == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final LinkHandlerFactory streamLinkHandlerFactory = getService().getStreamLHFactory();
|
|
||||||
final TimeAgoParser timeAgoParser = getTimeAgoParser();
|
final TimeAgoParser timeAgoParser = getTimeAgoParser();
|
||||||
|
|
||||||
for (final Element li : element.children()) {
|
JsonArray videos = initialData.getObject("contents").getObject("twoColumnBrowseResultsRenderer")
|
||||||
if (isDeletedItem(li)) {
|
.getArray("tabs").getObject(0).getObject("tabRenderer").getObject("content")
|
||||||
continue;
|
.getObject("sectionListRenderer").getArray("contents").getObject(0)
|
||||||
|
.getObject("itemSectionRenderer").getArray("contents").getObject(0)
|
||||||
|
.getObject("playlistVideoListRenderer").getArray("contents");
|
||||||
|
|
||||||
|
for (Object video : videos) {
|
||||||
|
if (((JsonObject) video).getObject("playlistVideoRenderer") != null) {
|
||||||
|
collector.commit(new YoutubeStreamInfoItemExtractor(((JsonObject) video).getObject("playlistVideoRenderer"), timeAgoParser) {
|
||||||
|
@Override
|
||||||
|
public long getViewCount() {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
collector.commit(new YoutubeStreamInfoItemExtractor(li, timeAgoParser) {
|
|
||||||
public Element uploaderLink;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isAd() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getUrl() throws ParsingException {
|
|
||||||
try {
|
|
||||||
return streamLinkHandlerFactory.fromId(li.attr("data-video-id")).getUrl();
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new ParsingException("Could not get web page url for the video", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getName() throws ParsingException {
|
|
||||||
try {
|
|
||||||
return li.attr("data-title");
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new ParsingException("Could not get title", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getDuration() throws ParsingException {
|
|
||||||
try {
|
|
||||||
if (getStreamType() == StreamType.LIVE_STREAM) return -1;
|
|
||||||
|
|
||||||
Element first = li.select("div[class=\"timestamp\"] span").first();
|
|
||||||
if (first == null) {
|
|
||||||
// Video unavailable (private, deleted, etc.), this is a thing that happens specifically with playlists,
|
|
||||||
// because in other cases, those videos don't even show up
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return YoutubeParsingHelper.parseDurationString(first.text());
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new ParsingException("Could not get duration" + getUrl(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private Element getUploaderLink() {
|
|
||||||
// should always be present since we filter deleted items
|
|
||||||
if (uploaderLink == null) {
|
|
||||||
uploaderLink = li.select("div[class=pl-video-owner] a").first();
|
|
||||||
}
|
|
||||||
return uploaderLink;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getUploaderName() throws ParsingException {
|
|
||||||
return getUploaderLink().text();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getUploaderUrl() throws ParsingException {
|
|
||||||
// this url is not always in the form "/channel/..."
|
|
||||||
// sometimes Youtube provides urls in the from "/user/..."
|
|
||||||
return getUploaderLink().attr("abs:href");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getTextualUploadDate() {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getViewCount() throws ParsingException {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getThumbnailUrl() throws ParsingException {
|
|
||||||
try {
|
|
||||||
return "https://i.ytimg.com/vi/" + streamLinkHandlerFactory.fromUrl(getUrl()).getId() + "/hqdefault.jpg";
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new ParsingException("Could not get thumbnail url", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the playlist item is deleted
|
|
||||||
*
|
|
||||||
* @param li the list item
|
|
||||||
* @return true if the item is deleted
|
|
||||||
*/
|
|
||||||
private boolean isDeletedItem(Element li) {
|
|
||||||
return li.select("div[class=pl-video-owner] a").isEmpty();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package org.schabi.newpipe.extractor.services.youtube.extractors;
|
package org.schabi.newpipe.extractor.services.youtube.extractors;
|
||||||
|
|
||||||
import com.grack.nanojson.JsonObject;
|
import com.grack.nanojson.JsonObject;
|
||||||
import org.jsoup.nodes.Element;
|
|
||||||
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
||||||
import org.schabi.newpipe.extractor.localization.DateWrapper;
|
import org.schabi.newpipe.extractor.localization.DateWrapper;
|
||||||
import org.schabi.newpipe.extractor.localization.TimeAgoParser;
|
import org.schabi.newpipe.extractor.localization.TimeAgoParser;
|
||||||
|
@ -37,10 +37,6 @@ public class YoutubeStreamInfoItemExtractor implements StreamInfoItemExtractor {
|
||||||
private JsonObject videoInfo;
|
private JsonObject videoInfo;
|
||||||
private final TimeAgoParser timeAgoParser;
|
private final TimeAgoParser timeAgoParser;
|
||||||
|
|
||||||
public YoutubeStreamInfoItemExtractor(Element a, @Nullable TimeAgoParser timeAgoParser) {
|
|
||||||
this.timeAgoParser = timeAgoParser;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an extractor of StreamInfoItems from a YouTube page.
|
* Creates an extractor of StreamInfoItems from a YouTube page.
|
||||||
*
|
*
|
||||||
|
@ -115,6 +111,12 @@ public class YoutubeStreamInfoItemExtractor implements StreamInfoItemExtractor {
|
||||||
.getObject(0).getString("text");
|
.getObject(0).getString("text");
|
||||||
} catch (Exception ignored) {}
|
} catch (Exception ignored) {}
|
||||||
}
|
}
|
||||||
|
if (name == null) {
|
||||||
|
try {
|
||||||
|
name = videoInfo.getObject("shortBylineText").getArray("runs")
|
||||||
|
.getObject(0).getString("text");
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
}
|
||||||
if (name != null && !name.isEmpty()) return name;
|
if (name != null && !name.isEmpty()) return name;
|
||||||
throw new ParsingException("Could not get uploader name");
|
throw new ParsingException("Could not get uploader name");
|
||||||
}
|
}
|
||||||
|
@ -135,6 +137,13 @@ public class YoutubeStreamInfoItemExtractor implements StreamInfoItemExtractor {
|
||||||
.getObject("browseEndpoint").getString("browseId");
|
.getObject("browseEndpoint").getString("browseId");
|
||||||
} catch (Exception ignored) {}
|
} catch (Exception ignored) {}
|
||||||
}
|
}
|
||||||
|
if (id == null) {
|
||||||
|
try {
|
||||||
|
id = videoInfo.getObject("shortBylineText").getArray("runs")
|
||||||
|
.getObject(0).getObject("navigationEndpoint")
|
||||||
|
.getObject("browseEndpoint").getString("browseId");
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
}
|
||||||
if (id == null || id.isEmpty()) {
|
if (id == null || id.isEmpty()) {
|
||||||
throw new IllegalArgumentException("is empty");
|
throw new IllegalArgumentException("is empty");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue