Skip to content
Merged
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 @@ -5,32 +5,32 @@
import org.schabi.newpipe.extractor.Image;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.playlist.PlaylistInfoItemExtractor;
import org.schabi.newpipe.extractor.utils.Utils;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;

import static org.schabi.newpipe.extractor.ListExtractor.ITEM_COUNT_MORE_THAN_100;
import static org.schabi.newpipe.extractor.ListExtractor.ITEM_COUNT_UNKNOWN;
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getTextFromObject;
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getImagesFromThumbnailsArray;
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getUrlFromNavigationEndpoint;
import static org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeSearchQueryHandlerFactory.MUSIC_ALBUMS;
import static org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeSearchQueryHandlerFactory.MUSIC_PLAYLISTS;
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;

public class YoutubeMusicAlbumOrPlaylistInfoItemExtractor implements PlaylistInfoItemExtractor {
private final JsonObject albumOrPlaylistInfoItem;
private final JsonArray descriptionElements;
private final String searchType;
private final JsonObject descriptionElementUploader;

public YoutubeMusicAlbumOrPlaylistInfoItemExtractor(final JsonObject albumOrPlaylistInfoItem,
final JsonArray descriptionElements,
final String searchType) {
this.albumOrPlaylistInfoItem = albumOrPlaylistInfoItem;
this.descriptionElements = descriptionElements;
this.searchType = searchType;

this.descriptionElementUploader = descriptionElements.getObject(
// For albums: "Album/Single/EP", " • ", uploader, " • ", year -> uploader is at 2
// For playlists: uploader, " • ", view count -> uploader is at 0
MUSIC_ALBUMS.equals(searchType) ? 2 : 0
);
}

@Nonnull
Expand Down Expand Up @@ -92,12 +92,7 @@ public String getUrl() throws ParsingException {

@Override
public String getUploaderName() throws ParsingException {
final String name;
if (searchType.equals(MUSIC_ALBUMS)) {
name = descriptionElements.getObject(2).getString("text");
} else {
name = descriptionElements.getObject(0).getString("text");
}
final String name = descriptionElementUploader.getString("text");

if (!isNullOrEmpty(name)) {
return name;
Expand All @@ -109,10 +104,7 @@ public String getUploaderName() throws ParsingException {
@Nullable
@Override
public String getUploaderUrl() throws ParsingException {
if (searchType.equals(MUSIC_PLAYLISTS)) {
return null;
}

// first try obtaining the uploader from the menu (will not work for MUSIC_PLAYLISTS though)
final JsonArray items = albumOrPlaylistInfoItem.getObject("menu")
.getObject("menuRenderer")
.getArray("items");
Expand All @@ -127,7 +119,14 @@ public String getUploaderUrl() throws ParsingException {
}
}

throw new ParsingException("Could not get uploader URL");
// then try obtaining it from the uploader description element
if (!descriptionElementUploader.has("navigationEndpoint")) {
// if there is no navigationEndpoint for the uploader
// then this playlist/album is likely autogenerated
return null;
}
return getUrlFromNavigationEndpoint(
descriptionElementUploader.getObject("navigationEndpoint"));
}

@Override
Expand All @@ -137,21 +136,7 @@ public boolean isUploaderVerified() throws ParsingException {

@Override
public long getStreamCount() throws ParsingException {
if (searchType.equals(MUSIC_ALBUMS)) {
return ITEM_COUNT_UNKNOWN;
}

final String count = descriptionElements.getObject(2)
.getString("text");

if (!isNullOrEmpty(count)) {
if (count.contains("100+")) {
return ITEM_COUNT_MORE_THAN_100;
} else {
return Long.parseLong(Utils.removeNonDigitCharacters(count));
}
}

throw new ParsingException("Could not get stream count");
// YouTube Music album and playlist info items don't expose the stream count anywhere...
return ITEM_COUNT_UNKNOWN;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,9 @@ protected SearchExtractor createExtractor() throws Exception {
}

public static class MusicAlbums extends DefaultSearchExtractorTest implements InitYoutubeTest {
private static final String QUERY = "johnny sellah";
// searching for "scenography" on 28/07/2025 returns some autogenerated albums,
// and we want to test the extraction of those, too
private static final String QUERY = "scenography";

@Override
protected SearchExtractor createExtractor() throws Exception {
Expand Down

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Loading