Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ public final class ChannelTabs {
public static final String LIVESTREAMS = "livestreams";
public static final String CHANNELS = "channels";
public static final String PLAYLISTS = "playlists";
public static final String PODCASTS = "podcasts";
public static final String ALBUMS = "albums";

private ChannelTabs() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -674,8 +674,7 @@ private JsonObject getVideoTab() throws ParsingException {
.getObject("commandMetadata").getObject("webCommandMetadata")
.getString("url");
if (tabUrl != null) {
final String[] urlParts = tabUrl.split("/");
final String urlSuffix = urlParts[urlParts.length - 1];
final String urlSuffix = normalizeTabSuffix(tabUrl);

switch (urlSuffix) {
case "videos":
Expand All @@ -685,6 +684,9 @@ private JsonObject getVideoTab() throws ParsingException {
case "playlists":
addTab.accept(ChannelTabs.PLAYLISTS);
break;
case "podcasts":
addTab.accept(ChannelTabs.PODCASTS);
break;
case "streams":
addTab.accept(ChannelTabs.LIVESTREAMS);
break;
Expand Down Expand Up @@ -723,4 +725,29 @@ private JsonObject getVideoTab() throws ParsingException {
return foundVideoTab;
}

@Nonnull
private static String normalizeTabSuffix(@Nonnull final String tabUrl) {
String normalized = tabUrl;
final int queryIndex = normalized.indexOf('?');
if (queryIndex >= 0) {
normalized = normalized.substring(0, queryIndex);
}

final int fragmentIndex = normalized.indexOf('#');
if (fragmentIndex >= 0) {
normalized = normalized.substring(0, fragmentIndex);
}

while (normalized.endsWith("/")) {
normalized = normalized.substring(0, normalized.length() - 1);
}

final int slashIndex = normalized.lastIndexOf('/');
if (slashIndex < 0 || slashIndex == normalized.length() - 1) {
return normalized;
}

return normalized.substring(slashIndex + 1);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ private String getChannelTabsParameters() throws ParsingException {
return "EghyZWxlYXNlc_IGBQoDsgEA";
case ChannelTabs.PLAYLISTS:
return "EglwbGF5bGlzdHPyBgQKAkIA";
case ChannelTabs.PODCASTS:
return "Eghwb2RjYXN0c_IGBQoDugEA";
default:
throw new ParsingException("Unsupported channel tab: " + name);
}
Expand Down Expand Up @@ -197,9 +199,10 @@ private JsonObject getTabData() throws ParsingException {
JsonObject foundTab = null;
for (final Object tab : tabs) {
if (((JsonObject) tab).has("tabRenderer")) {
if (((JsonObject) tab).getObject("tabRenderer").getObject("endpoint")
final String tabUrl = ((JsonObject) tab).getObject("tabRenderer").getObject("endpoint")
.getObject("commandMetadata").getObject("webCommandMetadata")
.getString("url").endsWith(urlSuffix)) {
.getString("url");
if (tabUrl != null && normalizeTabUrl(tabUrl).endsWith(urlSuffix)) {
foundTab = ((JsonObject) tab).getObject("tabRenderer");
break;
}
Expand Down Expand Up @@ -309,6 +312,11 @@ public String getUploaderName() {
return channelIds.get(0);
}
});
} else if (richItem.has("lockupViewModel")) {
commitLockupItemIfSupported(collector,
richItem.getObject("lockupViewModel"), channelIds);
} else {
return collectItem(collector, richItem, channelIds);
}
} else if (item.has("gridPlaylistRenderer")) {
collector.commit(new YoutubePlaylistInfoItemExtractor(
Expand All @@ -318,6 +326,12 @@ public String getUploaderName() {
return channelIds.get(0);
}
});
} else if (item.has("playlistRenderer")) {
collector.commit(new YoutubeMixOrPlaylistInfoItemExtractor(
item.getObject("playlistRenderer")));
} else if (item.has("radioRenderer")) {
collector.commit(new YoutubeMixOrPlaylistInfoItemExtractor(
item.getObject("radioRenderer")));
} else if (item.has("gridChannelRenderer")) {
collector.commit(new YoutubeChannelInfoItemExtractor(
item.getObject("gridChannelRenderer")));
Expand All @@ -336,23 +350,73 @@ public String getUploaderName() {
} else if (item.has("continuationItemRenderer")) {
return item.getObject("continuationItemRenderer");
} else if (item.has("lockupViewModel")) {
final JsonObject lockupViewModel = item.getObject("lockupViewModel");
final String contentType = lockupViewModel.getString("contentType");
if ("LOCKUP_CONTENT_TYPE_PLAYLIST".equals(contentType)
|| "LOCKUP_CONTENT_TYPE_PODCAST".equals(contentType)) {
String channelName;
try {
channelName = getChannelName();
} catch (Exception e) {
channelName = channelIds.get(0);
}
commitPlaylistLockup(collector, lockupViewModel,
channelName, null);
}
commitLockupItemIfSupported(collector,
item.getObject("lockupViewModel"), channelIds);
}
return null;
}

private void commitLockupItemIfSupported(@Nonnull final MultiInfoItemsCollector collector,
@Nonnull final JsonObject lockupViewModel,
@Nonnull final List<String> channelIds) {
final String contentType = lockupViewModel.getString("contentType");
if ("LOCKUP_CONTENT_TYPE_PLAYLIST".equals(contentType)
|| "LOCKUP_CONTENT_TYPE_PODCAST".equals(contentType)) {
String channelName;
try {
channelName = getChannelName();
} catch (final Exception e) {
channelName = channelIds.get(0);
}
commitPlaylistLockup(collector, lockupViewModel, channelName, null);
return;
}

if ("LOCKUP_CONTENT_TYPE_VIDEO".equals(contentType)
|| "LOCKUP_CONTENT_TYPE_EPISODE".equals(contentType)) {
collector.commit(new YoutubeLockupStreamInfoItemExtractor(lockupViewModel,
getTimeAgoParser()) {
@Override
public String getUploaderName() throws ParsingException {
try {
return super.getUploaderName();
} catch (final ParsingException e) {
return channelIds.get(0);
}
}

@Override
public String getUploaderUrl() throws ParsingException {
try {
return super.getUploaderUrl();
} catch (final ParsingException e) {
return channelIds.get(1);
}
}
});
}
}

@Nonnull
private static String normalizeTabUrl(@Nonnull final String tabUrl) {
String normalized = tabUrl;
final int queryIndex = normalized.indexOf('?');
if (queryIndex >= 0) {
normalized = normalized.substring(0, queryIndex);
}

final int fragmentIndex = normalized.indexOf('#');
if (fragmentIndex >= 0) {
normalized = normalized.substring(0, fragmentIndex);
}

while (normalized.endsWith("/")) {
normalized = normalized.substring(0, normalized.length() - 1);
}

return normalized;
}

@Nullable
private Page getNextPageFrom(final JsonObject continuations,
final List<String> channelIds) throws IOException,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ public static String getUrlSuffix(final String tab) throws ParsingException {
return "/videos";
case ChannelTabs.PLAYLISTS:
return "/playlists";
case ChannelTabs.PODCASTS:
return "/podcasts";
case ChannelTabs.LIVESTREAMS:
return "/streams";
case ChannelTabs.SHORTS:
Expand Down