Skip to content

Commit b5e50cc

Browse files
authored
Merge pull request #484 from TeamNewPipe/yt_,music_search
Fix YouTube Music search
2 parents abee0a8 + d9e2da5 commit b5e50cc

5 files changed

Lines changed: 61 additions & 34 deletions

File tree

extractor/src/main/java/org/schabi/newpipe/extractor/linkhandler/ListLinkHandlerFactory.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ public ListLinkHandler fromQuery(String id,
7474
* however it should not be overridden by the actual implementation.
7575
*
7676
* @param id
77-
* @return the url coresponding to id without any filters applied
77+
* @return the url corresponding to id without any filters applied
7878
*/
7979
public String getUrl(String id) throws ParsingException {
8080
return getUrl(id, new ArrayList<String>(0), "");

extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeParsingHelper.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -205,12 +205,12 @@ public static boolean isYoutubeMixId(final String playlistId) {
205205

206206
/**
207207
* Checks if the given playlist id is a YouTube Music Mix (auto-generated playlist)
208-
* Ids from a YouTube Music Mix start with "RDAMVM"
208+
* Ids from a YouTube Music Mix start with "RDAMVM" or "RDCLAK"
209209
* @param playlistId
210210
* @return Whether given id belongs to a YouTube Music Mix
211211
*/
212212
public static boolean isYoutubeMusicMixId(final String playlistId) {
213-
return playlistId.startsWith("RDAMVM");
213+
return playlistId.startsWith("RDAMVM") || playlistId.startsWith("RDCLAK");
214214
}
215215
/**
216216
* Checks if the given playlist id is a YouTube Channel Mix (auto-generated playlist)
@@ -226,20 +226,20 @@ public static boolean isYoutubeChannelMixId(final String playlistId) {
226226
* @throws ParsingException If the playlistId is a Channel Mix or not a mix.
227227
*/
228228
public static String extractVideoIdFromMixId(final String playlistId) throws ParsingException {
229-
if (playlistId.startsWith("RDMM")) { //My Mix
229+
if (playlistId.startsWith("RDMM")) { // My Mix
230230
return playlistId.substring(4);
231231

232-
} else if (playlistId.startsWith("RDAMVM")) { //Music mix
232+
} else if (isYoutubeMusicMixId(playlistId)) { // starts with "RDAMVM" or "RDCLAK"
233233
return playlistId.substring(6);
234234

235-
} else if (playlistId.startsWith("RMCM")) { //Channel mix
236-
//Channel mix are build with RMCM{channelId}, so videoId can't be determined
235+
} else if (isYoutubeChannelMixId(playlistId)) { // starts with "RMCM"
236+
// Channel mix are build with RMCM{channelId}, so videoId can't be determined
237237
throw new ParsingException("Video id could not be determined from mix id: " + playlistId);
238238

239-
} else if (playlistId.startsWith("RD")) { // Normal mix
239+
} else if (isYoutubeMixId(playlistId)) { // normal mix, starts with "RD"
240240
return playlistId.substring(2);
241241

242-
} else { //not a mix
242+
} else { // not a mix
243243
throw new ParsingException("Video id could not be determined from mix id: " + playlistId);
244244
}
245245
}

extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeService.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,8 @@ public ChannelExtractor getChannelExtractor(ListLinkHandler linkHandler) {
111111

112112
@Override
113113
public PlaylistExtractor getPlaylistExtractor(final ListLinkHandler linkHandler) {
114-
if (YoutubeParsingHelper.isYoutubeMixId(linkHandler.getId())) {
114+
if (YoutubeParsingHelper.isYoutubeMixId(linkHandler.getId())
115+
&& !YoutubeParsingHelper.isYoutubeMusicMixId(linkHandler.getId())) {
115116
return new YoutubeMixPlaylistExtractor(this, linkHandler);
116117
} else {
117118
return new YoutubePlaylistExtractor(this, linkHandler);

extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeMusicSearchExtractor.java

Lines changed: 50 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
import org.schabi.newpipe.extractor.search.InfoItemsSearchCollector;
2121
import org.schabi.newpipe.extractor.search.SearchExtractor;
2222
import org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper;
23+
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubePlaylistLinkHandlerFactory;
24+
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeStreamLinkHandlerFactory;
2325
import org.schabi.newpipe.extractor.utils.JsonUtils;
2426
import org.schabi.newpipe.extractor.utils.Utils;
2527

@@ -258,16 +260,29 @@ private void collectMusicStreamsFrom(final InfoItemsSearchCollector collector, f
258260
final TimeAgoParser timeAgoParser = getTimeAgoParser();
259261

260262
for (Object item : videos) {
261-
final JsonObject info = ((JsonObject) item).getObject("musicResponsiveListItemRenderer", null);
263+
final JsonObject info = ((JsonObject) item)
264+
.getObject("musicResponsiveListItemRenderer", null);
262265
if (info != null) {
266+
final String displayPolicy = info.getString("musicItemRendererDisplayPolicy", EMPTY_STRING);
267+
if (displayPolicy.equals("MUSIC_ITEM_RENDERER_DISPLAY_POLICY_GREY_OUT")) {
268+
continue; // no info about video URL available
269+
}
270+
271+
final JsonObject flexColumnRenderer = info
272+
.getArray("flexColumns")
273+
.getObject(1)
274+
.getObject("musicResponsiveListItemFlexColumnRenderer");
275+
final JsonArray descriptionElements = flexColumnRenderer
276+
.getObject("text")
277+
.getArray("runs");
263278
final String searchType = getLinkHandler().getContentFilters().get(0);
264279
if (searchType.equals(MUSIC_SONGS) || searchType.equals(MUSIC_VIDEOS)) {
265280
collector.commit(new YoutubeStreamInfoItemExtractor(info, timeAgoParser) {
266281
@Override
267282
public String getUrl() throws ParsingException {
268-
final String url = getUrlFromNavigationEndpoint(info.getObject("doubleTapCommand"));
269-
if (!isNullOrEmpty(url)) {
270-
return url;
283+
final String id = info.getObject("playlistItemData").getString("videoId");
284+
if (!isNullOrEmpty(id)) {
285+
return "https://music.youtube.com/watch?v=" + id;
271286
}
272287
throw new ParsingException("Could not get url");
273288
}
@@ -284,8 +299,9 @@ public String getName() throws ParsingException {
284299

285300
@Override
286301
public long getDuration() throws ParsingException {
287-
final String duration = getTextFromObject(info.getArray("flexColumns").getObject(3)
288-
.getObject("musicResponsiveListItemFlexColumnRenderer").getObject("text"));
302+
final String duration = descriptionElements
303+
.getObject(descriptionElements.size() - 1)
304+
.getString("text");
289305
if (!isNullOrEmpty(duration)) {
290306
return YoutubeParsingHelper.parseDurationString(duration);
291307
}
@@ -294,8 +310,7 @@ public long getDuration() throws ParsingException {
294310

295311
@Override
296312
public String getUploaderName() throws ParsingException {
297-
final String name = getTextFromObject(info.getArray("flexColumns").getObject(1)
298-
.getObject("musicResponsiveListItemFlexColumnRenderer").getObject("text"));
313+
final String name = descriptionElements.getObject(0).getString("text");
299314
if (!isNullOrEmpty(name)) {
300315
return name;
301316
}
@@ -346,8 +361,9 @@ public long getViewCount() throws ParsingException {
346361
if (searchType.equals(MUSIC_SONGS)) {
347362
return -1;
348363
}
349-
final String viewCount = getTextFromObject(info.getArray("flexColumns").getObject(2)
350-
.getObject("musicResponsiveListItemFlexColumnRenderer").getObject("text"));
364+
final String viewCount = descriptionElements
365+
.getObject(descriptionElements.size() - 3)
366+
.getString("text");
351367
if (!isNullOrEmpty(viewCount)) {
352368
return Utils.mixedNumberWordToLong(viewCount);
353369
}
@@ -451,9 +467,27 @@ public String getName() throws ParsingException {
451467

452468
@Override
453469
public String getUrl() throws ParsingException {
454-
final String url = getUrlFromNavigationEndpoint(info.getObject("doubleTapCommand"));
455-
if (!isNullOrEmpty(url)) {
456-
return url;
470+
String playlistId = info.getObject("menu")
471+
.getObject("menuRenderer")
472+
.getArray("items")
473+
.getObject(4)
474+
.getObject("toggleMenuServiceItemRenderer")
475+
.getObject("toggledServiceEndpoint")
476+
.getObject("likeEndpoint")
477+
.getObject("target")
478+
.getString("playlistId");
479+
480+
if (isNullOrEmpty(playlistId)) {
481+
playlistId = info.getObject("overlay")
482+
.getObject("musicItemThumbnailOverlayRenderer")
483+
.getObject("content")
484+
.getObject("musicPlayButtonRenderer")
485+
.getObject("playNavigationEndpoint")
486+
.getObject("watchPlaylistEndpoint")
487+
.getString("playlistId");
488+
}
489+
if (!isNullOrEmpty(playlistId)) {
490+
return "https://music.youtube.com/playlist?list=" + playlistId;
457491
}
458492
throw new ParsingException("Could not get url");
459493
}
@@ -462,11 +496,9 @@ public String getUrl() throws ParsingException {
462496
public String getUploaderName() throws ParsingException {
463497
final String name;
464498
if (searchType.equals(MUSIC_ALBUMS)) {
465-
name = getTextFromObject(info.getArray("flexColumns").getObject(2)
466-
.getObject("musicResponsiveListItemFlexColumnRenderer").getObject("text"));
499+
name = descriptionElements.getObject(2).getString("text");
467500
} else {
468-
name = getTextFromObject(info.getArray("flexColumns").getObject(1)
469-
.getObject("musicResponsiveListItemFlexColumnRenderer").getObject("text"));
501+
name = descriptionElements.getObject(0).getString("text");
470502
}
471503
if (!isNullOrEmpty(name)) {
472504
return name;
@@ -479,8 +511,7 @@ public long getStreamCount() throws ParsingException {
479511
if (searchType.equals(MUSIC_ALBUMS)) {
480512
return ITEM_COUNT_UNKNOWN;
481513
}
482-
final String count = getTextFromObject(info.getArray("flexColumns").getObject(2)
483-
.getObject("musicResponsiveListItemFlexColumnRenderer").getObject("text"));
514+
final String count = descriptionElements.getObject(2).getString("text");
484515
if (!isNullOrEmpty(count)) {
485516
if (count.contains("100+")) {
486517
return ITEM_COUNT_MORE_THAN_100;

extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/linkHandler/YoutubePlaylistLinkHandlerFactory.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,6 @@ public String getId(final String url) throws ParsingException {
5252
"the list-ID given in the URL does not match the list pattern");
5353
}
5454

55-
if (YoutubeParsingHelper.isYoutubeMusicMixId(listID)) {
56-
throw new ContentNotSupportedException(
57-
"YouTube Music Mix playlists are not yet supported");
58-
}
59-
6055
if (YoutubeParsingHelper.isYoutubeChannelMixId(listID)
6156
&& Utils.getQueryValue(urlObj, "v") == null) {
6257
//Video id can't be determined from the channel mix id. See YoutubeParsingHelper#extractVideoIdFromMixId

0 commit comments

Comments
 (0)