[YouTube] Parse watching count in live streams items
This commit is contained in:
parent
3638f0e0ea
commit
d8280ce0da
|
@ -304,12 +304,65 @@ public class YoutubeStreamExtractor extends StreamExtractor {
|
||||||
public long getViewCount() throws ParsingException {
|
public long getViewCount() throws ParsingException {
|
||||||
assertPageFetched();
|
assertPageFetched();
|
||||||
try {
|
try {
|
||||||
|
if (getStreamType().equals(StreamType.LIVE_STREAM)) {
|
||||||
|
return getLiveStreamWatchingCount();
|
||||||
|
}
|
||||||
|
|
||||||
return Long.parseLong(doc.select("meta[itemprop=interactionCount]").attr(CONTENT));
|
return Long.parseLong(doc.select("meta[itemprop=interactionCount]").attr(CONTENT));
|
||||||
} catch (Exception e) {//todo: find fallback method
|
} catch (Exception e) {//todo: find fallback method
|
||||||
throw new ParsingException("Could not get number of views", e);
|
throw new ParsingException("Could not get number of views", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private long getLiveStreamWatchingCount() throws ExtractionException, IOException, JsonParserException {
|
||||||
|
// https://www.youtube.com/youtubei/v1/updated_metadata?alt=json&key=
|
||||||
|
String innerTubeKey = null, clientVersion = null;
|
||||||
|
if (playerArgs != null && !playerArgs.isEmpty()) {
|
||||||
|
innerTubeKey = playerArgs.getString("innertube_api_key");
|
||||||
|
clientVersion = playerArgs.getString("innertube_context_client_version");
|
||||||
|
} else if (!videoInfoPage.isEmpty()) {
|
||||||
|
innerTubeKey = videoInfoPage.get("innertube_api_key");
|
||||||
|
clientVersion = videoInfoPage.get("innertube_context_client_version");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (innerTubeKey == null || innerTubeKey.isEmpty()) {
|
||||||
|
throw new ExtractionException("Couldn't get innerTube key");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clientVersion == null || clientVersion.isEmpty()) {
|
||||||
|
throw new ExtractionException("Couldn't get innerTube client version");
|
||||||
|
}
|
||||||
|
|
||||||
|
final String metadataUrl = "https://www.youtube.com/youtubei/v1/updated_metadata?alt=json&key=" + innerTubeKey;
|
||||||
|
final byte[] dataBody = ("{\"context\":{\"client\":{\"clientName\":1,\"clientVersion\":\"" + clientVersion + "\"}}" +
|
||||||
|
",\"videoId\":\"" + getId() + "\"}").getBytes("UTF-8");
|
||||||
|
final Response response = getDownloader().execute(Request.newBuilder()
|
||||||
|
.post(metadataUrl, dataBody)
|
||||||
|
.addHeader("Content-Type", "application/json")
|
||||||
|
.build());
|
||||||
|
final JsonObject jsonObject = JsonParser.object().from(response.responseBody());
|
||||||
|
|
||||||
|
for (Object actionEntry : jsonObject.getArray("actions")) {
|
||||||
|
if (!(actionEntry instanceof JsonObject)) continue;
|
||||||
|
final JsonObject entry = (JsonObject) actionEntry;
|
||||||
|
|
||||||
|
final JsonObject updateViewershipAction = entry.getObject("updateViewershipAction", null);
|
||||||
|
if (updateViewershipAction == null) continue;
|
||||||
|
|
||||||
|
final JsonArray viewCountRuns = JsonUtils.getArray(updateViewershipAction, "viewership.videoViewCountRenderer.viewCount.runs");
|
||||||
|
if (viewCountRuns.isEmpty()) continue;
|
||||||
|
|
||||||
|
final JsonObject textObject = viewCountRuns.getObject(0);
|
||||||
|
if (!textObject.has("text")) {
|
||||||
|
throw new ExtractionException("Response don't have \"text\" element");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Long.parseLong(Utils.removeNonDigitCharacters(textObject.getString("text")));
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new ExtractionException("Could not find correct results in response");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getLikeCount() throws ParsingException {
|
public long getLikeCount() throws ParsingException {
|
||||||
assertPageFetched();
|
assertPageFetched();
|
||||||
|
|
|
@ -3,10 +3,10 @@ package org.schabi.newpipe.extractor.services.youtube.extractors;
|
||||||
import org.jsoup.nodes.Element;
|
import org.jsoup.nodes.Element;
|
||||||
import org.jsoup.select.Elements;
|
import org.jsoup.select.Elements;
|
||||||
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
||||||
|
import org.schabi.newpipe.extractor.localization.TimeAgoParser;
|
||||||
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeParsingHelper;
|
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeParsingHelper;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfoItemExtractor;
|
import org.schabi.newpipe.extractor.stream.StreamInfoItemExtractor;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamType;
|
import org.schabi.newpipe.extractor.stream.StreamType;
|
||||||
import org.schabi.newpipe.extractor.localization.TimeAgoParser;
|
|
||||||
import org.schabi.newpipe.extractor.utils.Utils;
|
import org.schabi.newpipe.extractor.utils.Utils;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
@ -141,6 +141,10 @@ public class YoutubeStreamInfoItemExtractor implements StreamInfoItemExtractor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getTextualUploadDate() throws ParsingException {
|
public String getTextualUploadDate() throws ParsingException {
|
||||||
|
if (getStreamType().equals(StreamType.LIVE_STREAM)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
if (cachedUploadDate != null) {
|
if (cachedUploadDate != null) {
|
||||||
return cachedUploadDate;
|
return cachedUploadDate;
|
||||||
}
|
}
|
||||||
|
@ -160,9 +164,12 @@ public class YoutubeStreamInfoItemExtractor implements StreamInfoItemExtractor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Calendar getUploadDate() throws ParsingException {
|
public Calendar getUploadDate() throws ParsingException {
|
||||||
|
if (getStreamType().equals(StreamType.LIVE_STREAM)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
String textualUploadDate = getTextualUploadDate();
|
String textualUploadDate = getTextualUploadDate();
|
||||||
if (timeAgoParser != null
|
if (timeAgoParser != null && textualUploadDate != null && !textualUploadDate.isEmpty()) {
|
||||||
&& textualUploadDate != null && !"".equals(textualUploadDate)) {
|
|
||||||
return timeAgoParser.parse(textualUploadDate);
|
return timeAgoParser.parse(textualUploadDate);
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
|
@ -172,24 +179,35 @@ public class YoutubeStreamInfoItemExtractor implements StreamInfoItemExtractor {
|
||||||
@Override
|
@Override
|
||||||
public long getViewCount() throws ParsingException {
|
public long getViewCount() throws ParsingException {
|
||||||
String input;
|
String input;
|
||||||
try {
|
|
||||||
// TODO: Return the actual live stream's watcher count
|
|
||||||
// -1 for no view count
|
|
||||||
if (getStreamType() == StreamType.LIVE_STREAM) return -1;
|
|
||||||
|
|
||||||
|
if (getStreamType().equals(StreamType.LIVE_STREAM)) {
|
||||||
|
Element meta = item.select("ul[class=\"yt-lockup-meta-info\"]").first();
|
||||||
|
if (meta == null) return 0;
|
||||||
|
|
||||||
|
final Elements li = meta.select("li");
|
||||||
|
if (li.isEmpty()) return 0;
|
||||||
|
|
||||||
|
input = li.first().text();
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
Element meta = item.select("div[class=\"yt-lockup-meta\"]").first();
|
Element meta = item.select("div[class=\"yt-lockup-meta\"]").first();
|
||||||
if (meta == null) return -1;
|
if (meta == null) return -1;
|
||||||
|
|
||||||
// This case can happen if google releases a special video
|
// This case can happen if google releases a special video
|
||||||
if(meta.select("li").size() < 2) return -1;
|
if (meta.select("li").size() < 2) return -1;
|
||||||
|
|
||||||
input = meta.select("li").get(1).text();
|
input = meta.select("li").get(1).text();
|
||||||
|
|
||||||
} catch (IndexOutOfBoundsException e) {
|
} catch (IndexOutOfBoundsException e) {
|
||||||
throw new ParsingException("Could not parse yt-lockup-meta although available: " + getUrl(), e);
|
throw new ParsingException("Could not parse yt-lockup-meta although available: " + getUrl(), e);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input == null) {
|
||||||
|
throw new ParsingException("Input is null");
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
return Long.parseLong(Utils.removeNonDigitCharacters(input));
|
return Long.parseLong(Utils.removeNonDigitCharacters(input));
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
// if this happens the video probably has no views
|
// if this happens the video probably has no views
|
||||||
|
|
|
@ -68,7 +68,7 @@ public class YoutubeStreamExtractorLivestreamTest {
|
||||||
@Test
|
@Test
|
||||||
public void testGetViewCount() throws ParsingException {
|
public void testGetViewCount() throws ParsingException {
|
||||||
long count = extractor.getViewCount();
|
long count = extractor.getViewCount();
|
||||||
assertTrue(Long.toString(count), count >= 7148995);
|
assertTrue(Long.toString(count), count > -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
Loading…
Reference in New Issue