2
0
mirror of https://github.com/TeamNewPipe/NewPipeExtractor synced 2025-08-22 09:57:38 +00:00

[YouTube Music] Fix uploader and stream count for album/playlist info items

- handles autogenerated albums instead of returning an error for invalid uploader url
- extracts uploader url of playlists too using another method
- getStreamCount() now returns ITEM_COUNT_UNKNOWN because no info is included in the JSON
This commit is contained in:
Stypox 2025-07-28 17:43:51 +02:00
parent 260ba4749a
commit 03a65516b0
No known key found for this signature in database
GPG Key ID: 4BDF1B40A49FDD23
5 changed files with 417 additions and 114 deletions

View File

@ -5,32 +5,34 @@ import com.grack.nanojson.JsonObject;
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;
if (searchType.equals(MUSIC_ALBUMS)) {
// "Album", "", uploader, "", year
this.descriptionElementUploader = descriptionElements.getObject(2);
} else {
// uploader, "", view count
this.descriptionElementUploader = descriptionElements.getObject(0);
}
}
@Nonnull
@ -92,12 +94,7 @@ public class YoutubeMusicAlbumOrPlaylistInfoItemExtractor implements PlaylistInf
@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;
@ -109,10 +106,7 @@ public class YoutubeMusicAlbumOrPlaylistInfoItemExtractor implements PlaylistInf
@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");
@ -127,7 +121,15 @@ public class YoutubeMusicAlbumOrPlaylistInfoItemExtractor implements PlaylistInf
}
}
throw new ParsingException("Could not get uploader URL");
// then try obtaining it from the uploader description element
if (descriptionElementUploader.has("navigationEndpoint")) {
return getUrlFromNavigationEndpoint(
descriptionElementUploader.getObject("navigationEndpoint"));
} else {
// if there is no navigationEndpoint for the uploader
// then this playlist/album is likely autogenerated
return null;
}
}
@Override
@ -137,21 +139,7 @@ public class YoutubeMusicAlbumOrPlaylistInfoItemExtractor implements PlaylistInf
@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;
}
}

View File

@ -57,7 +57,9 @@ public class YoutubeMusicSearchExtractorTest {
}
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 {