Skip to content

Commit c1d40e2

Browse files
committed
Parse watching count in live streams items
1 parent e593adb commit c1d40e2

2 files changed

Lines changed: 81 additions & 14 deletions

File tree

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

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,12 +311,61 @@ public long getTimeStamp() throws ParsingException {
311311
public long getViewCount() throws ParsingException {
312312
assertPageFetched();
313313
try {
314+
if (getStreamType().equals(StreamType.LIVE_STREAM)) {
315+
return getLiveStreamWatchingCount();
316+
}
317+
314318
return Long.parseLong(doc.select("meta[itemprop=interactionCount]").attr(CONTENT));
315319
} catch (Exception e) {//todo: find fallback method
316320
throw new ParsingException("Could not get number of views", e);
317321
}
318322
}
319323

324+
private long getLiveStreamWatchingCount() throws ExtractionException, IOException, JsonParserException {
325+
// https://www.youtube.com/youtubei/v1/updated_metadata?alt=json&key=
326+
String innerTubeKey = null, clientVersion = null;
327+
if (playerArgs != null && !playerArgs.isEmpty()) {
328+
innerTubeKey = playerArgs.getString("innertube_api_key");
329+
clientVersion = playerArgs.getString("innertube_client_version");
330+
} else if (!videoInfoPage.isEmpty()) {
331+
innerTubeKey = videoInfoPage.get("innertube_api_key");
332+
clientVersion = videoInfoPage.get("innertube_client_version");
333+
}
334+
335+
if (innerTubeKey == null || innerTubeKey.isEmpty() || clientVersion == null || clientVersion.isEmpty()) {
336+
throw new ExtractionException("Couldn't get innerTube key");
337+
}
338+
339+
final String metadataUrl = "https://www.youtube.com/youtubei/v1/updated_metadata?alt=json&key=" + innerTubeKey;
340+
final byte[] dataBody = ("{\"context\":{\"client\":{\"clientName\":1,\"clientVersion\":\"" + clientVersion + "\"}}" +
341+
",\"videoId\":\"" + getId() + "\"}").getBytes("UTF-8");
342+
final Response response = getDownloader().execute(Request.newBuilder()
343+
.post(metadataUrl, dataBody)
344+
.addHeader("Content-Type", "application/json")
345+
.build());
346+
final JsonObject jsonObject = JsonParser.object().from(response.responseBody());
347+
348+
for (Object actionEntry : jsonObject.getArray("actions")) {
349+
if (!(actionEntry instanceof JsonObject)) continue;
350+
final JsonObject entry = (JsonObject) actionEntry;
351+
352+
final JsonObject updateViewershipAction = entry.getObject("updateViewershipAction", null);
353+
if (updateViewershipAction == null) continue;
354+
355+
final JsonArray viewCountRuns = JsonUtils.getArray(updateViewershipAction, "viewership.videoViewCountRenderer.viewCount.runs");
356+
if (viewCountRuns.isEmpty()) continue;
357+
358+
final JsonObject textObject = viewCountRuns.getObject(0);
359+
if (!textObject.has("text")) {
360+
throw new ExtractionException("Response don't have \"text\" element");
361+
}
362+
363+
return Long.parseLong(Utils.removeNonDigitCharacters(textObject.getString("text")));
364+
}
365+
366+
throw new ExtractionException("Could not find correct results in response");
367+
}
368+
320369
@Override
321370
public long getLikeCount() throws ParsingException {
322371
assertPageFetched();

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

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
import org.jsoup.nodes.Element;
44
import org.jsoup.select.Elements;
55
import org.schabi.newpipe.extractor.exceptions.ParsingException;
6+
import org.schabi.newpipe.extractor.localization.TimeAgoParser;
67
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeParsingHelper;
78
import org.schabi.newpipe.extractor.stream.StreamInfoItemExtractor;
89
import org.schabi.newpipe.extractor.stream.StreamType;
9-
import org.schabi.newpipe.extractor.localization.TimeAgoParser;
1010
import org.schabi.newpipe.extractor.utils.Utils;
1111

1212
import javax.annotation.Nullable;
@@ -141,6 +141,10 @@ public String getUploaderUrl() throws ParsingException {
141141

142142
@Override
143143
public String getTextualUploadDate() throws ParsingException {
144+
if (getStreamType().equals(StreamType.LIVE_STREAM)) {
145+
return null;
146+
}
147+
144148
if (cachedUploadDate != null) {
145149
return cachedUploadDate;
146150
}
@@ -160,9 +164,12 @@ public String getTextualUploadDate() throws ParsingException {
160164

161165
@Override
162166
public Calendar getUploadDate() throws ParsingException {
167+
if (getStreamType().equals(StreamType.LIVE_STREAM)) {
168+
return null;
169+
}
170+
163171
String textualUploadDate = getTextualUploadDate();
164-
if (timeAgoParser != null
165-
&& textualUploadDate != null && !"".equals(textualUploadDate)) {
172+
if (timeAgoParser != null && textualUploadDate != null && !textualUploadDate.isEmpty()) {
166173
return timeAgoParser.parse(textualUploadDate);
167174
} else {
168175
return null;
@@ -172,24 +179,35 @@ public Calendar getUploadDate() throws ParsingException {
172179
@Override
173180
public long getViewCount() throws ParsingException {
174181
String input;
175-
try {
176-
// TODO: Return the actual live stream's watcher count
177-
// -1 for no view count
178-
if (getStreamType() == StreamType.LIVE_STREAM) return -1;
179182

180-
Element meta = item.select("div[class=\"yt-lockup-meta\"]").first();
181-
if (meta == null) return -1;
183+
if (getStreamType().equals(StreamType.LIVE_STREAM)) {
184+
Element meta = item.select("ul[class=\"yt-lockup-meta-info\"]").first();
185+
if (meta == null) return 0;
186+
187+
final Elements li = meta.select("li");
188+
if (li.isEmpty()) return 0;
182189

183-
// This case can happen if google releases a special video
184-
if(meta.select("li").size() < 2) return -1;
190+
input = li.first().text();
191+
} else {
192+
try {
193+
Element meta = item.select("div[class=\"yt-lockup-meta\"]").first();
194+
if (meta == null) return -1;
185195

186-
input = meta.select("li").get(1).text();
196+
// This case can happen if google releases a special video
197+
if (meta.select("li").size() < 2) return -1;
187198

188-
} catch (IndexOutOfBoundsException e) {
189-
throw new ParsingException("Could not parse yt-lockup-meta although available: " + getUrl(), e);
199+
input = meta.select("li").get(1).text();
200+
} catch (IndexOutOfBoundsException e) {
201+
throw new ParsingException("Could not parse yt-lockup-meta although available: " + getUrl(), e);
202+
}
203+
}
204+
205+
if (input == null) {
206+
throw new ParsingException("Input is null");
190207
}
191208

192209
try {
210+
193211
return Long.parseLong(Utils.removeNonDigitCharacters(input));
194212
} catch (NumberFormatException e) {
195213
// if this happens the video probably has no views

0 commit comments

Comments
 (0)