2
0
mirror of https://github.com/TeamNewPipe/NewPipeExtractor synced 2025-08-22 01:48:58 +00:00

Compare commits

...

3 Commits

Author SHA1 Message Date
Tobi
a5fcc7d7aa
Merge pull request #1351 from Stypox/fix-ytm-albums-playlists
[YouTube Music] Fix uploader and stream count for album/playlist info items
2025-07-29 06:09:28 -07:00
Stypox
bd6e5d3fdb
Code style 2025-07-28 20:44:40 +02:00
Stypox
03a65516b0
[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
2025-07-28 17:43:53 +02:00
5 changed files with 414 additions and 114 deletions

View File

@ -5,32 +5,32 @@ 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;
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
@ -92,12 +92,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 +104,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 +119,14 @@ 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")) {
// if there is no navigationEndpoint for the uploader
// then this playlist/album is likely autogenerated
return null;
}
return getUrlFromNavigationEndpoint(
descriptionElementUploader.getObject("navigationEndpoint"));
}
@Override
@ -137,21 +136,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 {