[YouTube] Parse any playlist (including music mixes) in related items

This commit is contained in:
Stypox 2022-02-28 19:42:34 +01:00
parent 13f7900816
commit 8201b3b90e
No known key found for this signature in database
GPG Key ID: 4BDF1B40A49FDD23
10 changed files with 61 additions and 34 deletions

View File

@ -11,13 +11,14 @@ import org.schabi.newpipe.extractor.ListExtractor;
import org.schabi.newpipe.extractor.exceptions.ParsingException; import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.playlist.PlaylistInfo; import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
import org.schabi.newpipe.extractor.playlist.PlaylistInfoItemExtractor; import org.schabi.newpipe.extractor.playlist.PlaylistInfoItemExtractor;
import org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
public class YoutubeMixPlaylistInfoItemExtractor implements PlaylistInfoItemExtractor { public class YoutubeMixOrPlaylistInfoItemExtractor implements PlaylistInfoItemExtractor {
private final JsonObject mixInfoItem; private final JsonObject mixInfoItem;
public YoutubeMixPlaylistInfoItemExtractor(final JsonObject mixInfoItem) { public YoutubeMixOrPlaylistInfoItemExtractor(final JsonObject mixInfoItem) {
this.mixInfoItem = mixInfoItem; this.mixInfoItem = mixInfoItem;
} }
@ -46,15 +47,26 @@ public class YoutubeMixPlaylistInfoItemExtractor implements PlaylistInfoItemExtr
@Override @Override
public String getUploaderName() throws ParsingException { public String getUploaderName() throws ParsingException {
// YouTube mixes are auto-generated by YouTube // this will be "YouTube" for mixes
return "YouTube"; return YoutubeParsingHelper.getTextFromObject(mixInfoItem.getObject("longBylineText"));
} }
@Override @Override
public long getStreamCount() throws ParsingException { public long getStreamCount() throws ParsingException {
// Auto-generated playlists always start with 25 videos and are endless final String countString = YoutubeParsingHelper.getTextFromObject(
mixInfoItem.getObject("videoCountShortText"));
if (countString == null) {
throw new ParsingException("Could not extract item count for playlist/mix info item");
}
try {
return Integer.parseInt(countString);
} catch (final NumberFormatException ignored) {
// un-parsable integer: this is a mix with infinite items and "50+" as count string
// (though youtube music mixes do not necessarily have an infinite count of songs)
return ListExtractor.ITEM_COUNT_INFINITE; return ListExtractor.ITEM_COUNT_INFINITE;
} }
}
@Nonnull @Nonnull
@Override @Override

View File

@ -641,8 +641,11 @@ public class YoutubeStreamExtractor extends StreamExtractor {
collector.commit(new YoutubeStreamInfoItemExtractor( collector.commit(new YoutubeStreamInfoItemExtractor(
result.getObject("compactVideoRenderer"), timeAgoParser)); result.getObject("compactVideoRenderer"), timeAgoParser));
} else if (result.has("compactRadioRenderer")) { } else if (result.has("compactRadioRenderer")) {
collector.commit(new YoutubeMixPlaylistInfoItemExtractor( collector.commit(new YoutubeMixOrPlaylistInfoItemExtractor(
result.getObject("compactRadioRenderer"))); result.getObject("compactRadioRenderer")));
} else if (result.has("compactPlaylistRenderer")) {
collector.commit(new YoutubeMixOrPlaylistInfoItemExtractor(
result.getObject("compactPlaylistRenderer")));
} }
} }
return collector; return collector;

View File

@ -111,5 +111,17 @@ public class YoutubeStreamExtractorRelatedMixTest extends DefaultStreamExtractor
assertContains("list=RD" + ID, streamMix.getUrl()); assertContains("list=RD" + ID, streamMix.getUrl());
assertEquals("Mix " + TITLE, streamMix.getName()); assertEquals("Mix " + TITLE, streamMix.getName());
assertIsSecureUrl(streamMix.getThumbnailUrl()); assertIsSecureUrl(streamMix.getThumbnailUrl());
final List<PlaylistInfoItem> musicMixes = playlists.stream()
.filter(item -> item.getPlaylistType().equals(PlaylistType.MIX_MUSIC))
.collect(Collectors.toList());
assertEquals(1, musicMixes.size(), "Not found exactly one music mix in related items");
final PlaylistInfoItem musicMix = musicMixes.get(0);
assertSame(InfoItem.InfoType.PLAYLIST, musicMix.getInfoType());
assertEquals(YouTube.getServiceId(), musicMix.getServiceId());
assertContains("list=RDCLAK", musicMix.getUrl());
assertEquals("Hip Hop Essentials", musicMix.getName());
assertIsSecureUrl(musicMix.getThumbnailUrl());
} }
} }

View File

@ -32,10 +32,10 @@
"cross-origin" "cross-origin"
], ],
"date": [ "date": [
"Mon, 28 Feb 2022 18:18:09 GMT" "Mon, 28 Feb 2022 18:41:20 GMT"
], ],
"expires": [ "expires": [
"Mon, 28 Feb 2022 18:18:09 GMT" "Mon, 28 Feb 2022 18:41:20 GMT"
], ],
"p3p": [ "p3p": [
"CP\u003d\"This is not a P3P policy! See http://support.google.com/accounts/answer/151657?hl\u003den-GB for more info.\"" "CP\u003d\"This is not a P3P policy! See http://support.google.com/accounts/answer/151657?hl\u003den-GB for more info.\""
@ -50,9 +50,9 @@
"ESF" "ESF"
], ],
"set-cookie": [ "set-cookie": [
"YSC\u003dXQZxEN8iFpc; Domain\u003d.youtube.com; Path\u003d/; Secure; HttpOnly; SameSite\u003dnone", "YSC\u003dRRetMyo289w; Domain\u003d.youtube.com; Path\u003d/; Secure; HttpOnly; SameSite\u003dnone",
"VISITOR_INFO1_LIVE\u003dPdecpxhX70w; Domain\u003d.youtube.com; Expires\u003dSat, 27-Aug-2022 18:18:09 GMT; Path\u003d/; Secure; HttpOnly; SameSite\u003dnone", "VISITOR_INFO1_LIVE\u003d65TC-XopBj0; Domain\u003d.youtube.com; Expires\u003dSat, 27-Aug-2022 18:41:20 GMT; Path\u003d/; Secure; HttpOnly; SameSite\u003dnone",
"CONSENT\u003dPENDING+810; expires\u003dWed, 28-Feb-2024 18:18:09 GMT; path\u003d/; domain\u003d.youtube.com; Secure" "CONSENT\u003dPENDING+472; expires\u003dWed, 28-Feb-2024 18:41:20 GMT; path\u003d/; domain\u003d.youtube.com; Secure"
], ],
"strict-transport-security": [ "strict-transport-security": [
"max-age\u003d31536000" "max-age\u003d31536000"

View File

@ -20,7 +20,7 @@
"bytes" "bytes"
], ],
"age": [ "age": [
"353237" "354628"
], ],
"alt-svc": [ "alt-svc": [
"h3\u003d\":443\"; ma\u003d2592000,h3-29\u003d\":443\"; ma\u003d2592000,h3-Q050\u003d\":443\"; ma\u003d2592000,h3-Q046\u003d\":443\"; ma\u003d2592000,h3-Q043\u003d\":443\"; ma\u003d2592000,quic\u003d\":443\"; ma\u003d2592000; v\u003d\"46,43\"" "h3\u003d\":443\"; ma\u003d2592000,h3-29\u003d\":443\"; ma\u003d2592000,h3-Q050\u003d\":443\"; ma\u003d2592000,h3-Q046\u003d\":443\"; ma\u003d2592000,h3-Q043\u003d\":443\"; ma\u003d2592000,quic\u003d\":443\"; ma\u003d2592000; v\u003d\"46,43\""