diff --git a/gmusicapi/clients/mobileclient.py b/gmusicapi/clients/mobileclient.py index 33dafbf7..f5b0f59e 100644 --- a/gmusicapi/clients/mobileclient.py +++ b/gmusicapi/clients/mobileclient.py @@ -1681,7 +1681,7 @@ def search(self, query, max_results=None): A value of ``None`` allows up to 999 results per type. Default is ``None``. The results are returned in a dictionary with keys: - ``album_hits, artist_hits, playlist_hits, podcast_hits, + ``album_hits, artist_hits, genre_hits, playlist_hits, podcast_hits, situation_hits, song_hits, station_hits, video_hits`` containing lists of results of that type. @@ -1879,15 +1879,19 @@ def search(self, query, max_results=None): res = self._make_call(mobileclient.Search, query, max_results) - hits = res.get('entries', []) + clusters = res.get('clusterDetail', []) hits_by_type = defaultdict(list) - for hit in hits: - hits_by_type[hit['type']].append(hit) + for cluster in clusters: + hit_type = cluster['cluster']['type'] + hits = cluster.get('entries', []) + for hit in hits: + hits_by_type[hit_type].append(hit) return {'album_hits': hits_by_type['3'], 'artist_hits': hits_by_type['2'], 'playlist_hits': hits_by_type['4'], + 'genre_hits': hits_by_type['5'], 'podcast_hits': hits_by_type['9'], 'situation_hits': hits_by_type['7'], 'song_hits': hits_by_type['1'], diff --git a/gmusicapi/protocol/mobileclient.py b/gmusicapi/protocol/mobileclient.py index 12735a8c..2fecba91 100644 --- a/gmusicapi/protocol/mobileclient.py +++ b/gmusicapi/protocol/mobileclient.py @@ -595,6 +595,16 @@ 'items': sj_situation } +sj_search_result_cluster_info = { + 'type': 'object', + 'additionalProperties': False, + 'properties': { + 'category': {'type': 'string'}, + 'id': {'type': 'string'}, + 'type': {'type': 'string'} + } +} + sj_search_result = { 'type': 'object', 'additionalProperties': False, @@ -604,10 +614,16 @@ 'best_result': {'type': 'boolean', 'required': False}, 'navigational_result': {'type': 'boolean', 'required': False}, 'navigational_confidence': {'type': 'number', 'required': False}, + 'cluster': { + 'type': 'array', + 'required': False, + 'items': sj_search_result_cluster_info + }, 'artist': sj_artist.copy(), 'album': sj_album.copy(), 'track': sj_track.copy(), 'playlist': sj_playlist.copy(), + 'genre': sj_genre.copy(), 'series': sj_podcast_series.copy(), 'station': sj_station.copy(), 'situation': sj_situation.copy(), @@ -619,11 +635,27 @@ sj_search_result['properties']['album']['required'] = False sj_search_result['properties']['track']['required'] = False sj_search_result['properties']['playlist']['required'] = False +sj_search_result['properties']['genre']['required'] = False sj_search_result['properties']['series']['required'] = False sj_search_result['properties']['station']['required'] = False sj_search_result['properties']['situation']['required'] = False sj_search_result['properties']['youtube_video']['required'] = False +sj_search_result_cluster = { + 'type': 'object', + 'additionalProperties': False, + 'properties': { + 'cluster': {'type': sj_search_result_cluster_info}, + 'displayName': {'type': 'string', 'required': False}, + 'entries': { + 'type': 'array', + 'items': sj_search_result, + 'required': False + }, + 'resultToken': {'type': 'string', 'required': False} + } +} + class McCall(Call): """Abstract base for mobile client calls.""" @@ -865,22 +897,17 @@ class Search(McCall): # The result types returned are requested in the `ct` parameter. # Free account search is restricted so may not contain hits for all result types. - # 1: Song, 2: Artist, 3: Album, 4: Playlist, 6: Station, 7: Situation, 8: Video - # 9: Podcast Series - static_params = {'ct': '1,2,3,4,6,7,8,9'} + # 1: Song, 2: Artist, 3: Album, 4: Playlist, 5: Genre, + # 6: Station, 7: Situation, 8: Video, 9: Podcast Series + static_params = {'ct': '1,2,3,4,5,6,7,8,9', 'ic': True} _res_schema = { 'type': 'object', 'additionalProperties': False, 'properties': { 'kind': {'type': 'string'}, - 'clusterOrder': {'type': 'array', - 'items': {'type': 'string'}, - 'required': False}, - 'entries': {'type': 'array', - 'items': sj_search_result, - 'required': False}, - 'suggestedQuery': {'type': 'string', 'required': False} + 'clusterDetail': {'type': 'array', + 'items': {'type': sj_search_result_cluster}} }, }