Skip to content

Commit 996eb04

Browse files
authored
Merge pull request #1203 from AudricV/yt_support-shows-and-pageheader-on-user-channels
[YouTube] Support shows and page header on user channels
2 parents 2d36945 + 8db7249 commit 996eb04

12 files changed

Lines changed: 2009 additions & 1628 deletions

File tree

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

Lines changed: 247 additions & 14 deletions
Large diffs are not rendered by default.

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

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -825,9 +825,15 @@ public static String getUrlFromNavigationEndpoint(
825825
final String canonicalBaseUrl = browseEndpoint.getString("canonicalBaseUrl");
826826
final String browseId = browseEndpoint.getString("browseId");
827827

828-
// All channel ids are prefixed with UC
829-
if (browseId != null && browseId.startsWith("UC")) {
830-
return "https://www.youtube.com/channel/" + browseId;
828+
if (browseId != null) {
829+
if (browseId.startsWith("UC")) {
830+
// All channel IDs are prefixed with UC
831+
return "https://www.youtube.com/channel/" + browseId;
832+
} else if (browseId.startsWith("VL")) {
833+
// All playlist IDs are prefixed with VL, which needs to be removed from the
834+
// playlist ID
835+
return "https://www.youtube.com/playlist?list=" + browseId.substring(2);
836+
}
831837
}
832838

833839
if (!isNullOrEmpty(canonicalBaseUrl)) {
@@ -887,12 +893,13 @@ public static String getTextFromObject(final JsonObject textObject, final boolea
887893
return textObject.getString("simpleText");
888894
}
889895

890-
if (textObject.getArray("runs").isEmpty()) {
896+
final JsonArray runs = textObject.getArray("runs");
897+
if (runs.isEmpty()) {
891898
return null;
892899
}
893900

894901
final StringBuilder textBuilder = new StringBuilder();
895-
for (final Object o : textObject.getArray("runs")) {
902+
for (final Object o : runs) {
896903
final JsonObject run = (JsonObject) o;
897904
String text = run.getString("text");
898905

@@ -970,11 +977,12 @@ public static String getUrlFromObject(final JsonObject textObject) {
970977
return null;
971978
}
972979

973-
if (textObject.getArray("runs").isEmpty()) {
980+
final JsonArray runs = textObject.getArray("runs");
981+
if (runs.isEmpty()) {
974982
return null;
975983
}
976984

977-
for (final Object textPart : textObject.getArray("runs")) {
985+
for (final Object textPart : runs) {
978986
final String url = getUrlFromNavigationEndpoint(((JsonObject) textPart)
979987
.getObject("navigationEndpoint"));
980988
if (!isNullOrEmpty(url)) {
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package org.schabi.newpipe.extractor.services.youtube.extractors;
2+
3+
import com.grack.nanojson.JsonObject;
4+
import org.schabi.newpipe.extractor.Image;
5+
import org.schabi.newpipe.extractor.exceptions.ParsingException;
6+
import org.schabi.newpipe.extractor.playlist.PlaylistInfoItemExtractor;
7+
import org.schabi.newpipe.extractor.utils.Utils;
8+
9+
import javax.annotation.Nonnull;
10+
import java.util.List;
11+
12+
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getTextFromObject;
13+
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getThumbnailsFromInfoItem;
14+
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getUrlFromNavigationEndpoint;
15+
16+
/**
17+
* The base {@link PlaylistInfoItemExtractor} for shows playlists UI elements.
18+
*/
19+
abstract class YoutubeBaseShowInfoItemExtractor implements PlaylistInfoItemExtractor {
20+
21+
@Nonnull
22+
protected final JsonObject showRenderer;
23+
24+
YoutubeBaseShowInfoItemExtractor(@Nonnull final JsonObject showRenderer) {
25+
this.showRenderer = showRenderer;
26+
}
27+
28+
@Override
29+
public String getName() throws ParsingException {
30+
return showRenderer.getString("title");
31+
}
32+
33+
@Override
34+
public String getUrl() throws ParsingException {
35+
return getUrlFromNavigationEndpoint(showRenderer.getObject("navigationEndpoint"));
36+
}
37+
38+
@Nonnull
39+
@Override
40+
public List<Image> getThumbnails() throws ParsingException {
41+
return getThumbnailsFromInfoItem(showRenderer.getObject("thumbnailRenderer")
42+
.getObject("showCustomThumbnailRenderer"));
43+
}
44+
45+
@Override
46+
public long getStreamCount() throws ParsingException {
47+
// The stream count should be always returned in the first text object for English
48+
// localizations, but the complete text is parsed for reliability purposes
49+
final String streamCountText = getTextFromObject(
50+
showRenderer.getObject("thumbnailOverlays")
51+
.getObject("thumbnailOverlayBottomPanelRenderer")
52+
.getObject("text"));
53+
if (streamCountText == null) {
54+
throw new ParsingException("Could not get stream count");
55+
}
56+
57+
try {
58+
// The data returned could be a human/shortened number, but no show with more than 1000
59+
// videos has been found at the time this code was written
60+
return Long.parseLong(Utils.removeNonDigitCharacters(streamCountText));
61+
} catch (final NumberFormatException e) {
62+
throw new ParsingException("Could not convert stream count to a long", e);
63+
}
64+
}
65+
}

0 commit comments

Comments
 (0)