11from ._utils import *
22from .songs import *
33
4+ UNIQUE_RESULT_TYPES = ["artist" , "playlist" , "song" , "video" , "station" , "profile" , "podcast" , "episode" ]
5+ ALL_RESULT_TYPES = ["album" , * UNIQUE_RESULT_TYPES ]
6+
47
58def get_search_result_type (result_type_local , result_types_local ):
69 if not result_type_local :
710 return None
8- result_types = ["artist" , "playlist" , "song" , "video" , "station" , "profile" , "podcast" , "episode" ]
911 result_type_local = result_type_local .lower ()
1012 # default to album since it's labeled with multiple values ('Single', 'EP', etc.)
1113 if result_type_local not in result_types_local :
1214 result_type = "album"
1315 else :
14- result_type = result_types [result_types_local .index (result_type_local )]
16+ result_type = UNIQUE_RESULT_TYPES [result_types_local .index (result_type_local )]
1517
1618 return result_type
1719
@@ -39,7 +41,7 @@ def parse_top_result(data, search_result_types):
3941
4042 search_result ["title" ] = nav (data , TITLE_TEXT )
4143 runs = nav (data , ["subtitle" , "runs" ])
42- song_info = parse_song_runs (runs )
44+ song_info = parse_song_runs (runs [ 2 :] )
4345 search_result .update (song_info )
4446
4547 if result_type in ["album" ]:
@@ -58,14 +60,29 @@ def parse_search_result(data, search_result_types, result_type, category):
5860 default_offset = (not result_type or result_type == "album" ) * 2
5961 search_result = {"category" : category }
6062 video_type = nav (data , [* PLAY_BUTTON , "playNavigationEndpoint" , * NAVIGATION_VIDEO_TYPE ], True )
61- if not result_type and video_type :
62- result_type = "song" if video_type == "MUSIC_VIDEO_TYPE_ATV" else "video"
63-
64- result_type = (
65- get_search_result_type (get_item_text (data , 1 ), search_result_types )
66- if not result_type
67- else result_type
68- )
63+
64+ # try to determine the result type based on the first run
65+ if result_type not in ALL_RESULT_TYPES : # i.e. localized result_type
66+ result_type = get_search_result_type (get_item_text (data , 1 ), search_result_types )
67+
68+ # determine result type based on browseId
69+ # if there was no category title (i.e. for extra results in Top Result)
70+ if not result_type :
71+ if browse_id := nav (data , NAVIGATION_BROWSE_ID , True ):
72+ mapping = {
73+ "VMPL" : "playlist" ,
74+ "RD" : "playlist" ,
75+ "MPLA" : "artist" ,
76+ "MPRE" : "album" ,
77+ "MPSP" : "podcast" ,
78+ "MPED" : "episode" ,
79+ }
80+ result_type = next (
81+ iter (type for prefix , type in mapping .items () if browse_id .startswith (prefix )), None
82+ )
83+ else :
84+ result_type = "song" if video_type == "MUSIC_VIDEO_TYPE_ATV" else "video"
85+
6986 search_result ["resultType" ] = result_type
7087
7188 if result_type != "artist" :
@@ -134,7 +151,8 @@ def parse_search_result(data, search_result_types, result_type, category):
134151 search_result ["year" ] = None
135152 flex_item = get_flex_column_item (data , 1 )
136153 runs = flex_item ["text" ]["runs" ]
137- song_info = parse_song_runs (runs )
154+ runs_offset = (len (runs [0 ]) == 1 ) * 2 # ignore the first run if it is a type specifier (like "Song")
155+ song_info = parse_song_runs (runs [runs_offset :])
138156 search_result .update (song_info )
139157
140158 if result_type in ["artist" , "album" , "playlist" , "profile" , "podcast" ]:
0 commit comments