getArtist method

Future<JsonMap> getArtist(
  1. String channelId
)

Get information about an artist and their top releases (songs, albums, singles, videos, and related artists).

The top lists contain pointers for getting the full list of releases.

Possible content types for getArtist are:

  • songs
  • albums
  • singles
  • shows
  • videos
  • episodes
  • podcasts
  • related

Each of these content keys in the response contains results and possibly browseId and params:

Arguments:

  • channelId channel id of the artist.

Returns Map with requested information.

WARNING:

  • The returned channelId is not the same as the one passed to the function. It should be used only with subscribeArtist. // TODO subscribeArtist is currently missing

Example:

{
  "description": "Oasis were ...",
  "descriptionRuns": [
    {
      "text":"Oasis were ..."
    }
  ],
  "views": "3,693,390,359 views",
  "name": "Oasis",
  "channelId": "UCUDVBtnOQi4c7E8jebpjc9Q",
  "shuffleId": "RDAOkjHYJjL1a3xspEyVkhHAsg",
  "radioId": "RDEMkjHYJjL1a3xspEyVkhHAsg",
  "subscribers": "3.86M",
  "monthlyListeners": "29.1M",
  "subscribed": false,
  "thumbnails": [...],
  "songs": {
    "browseId": "VLPLMpM3Z0118S42R1npOhcjoakLIv1aqnS1",
    "results": [
      {
        "videoId": "ZrOKjDZOtkA",
        "title": "Wonderwall (Remastered)",
        "thumbnails": [...],
        "artist": "Oasis",
        "album": "(What's The Story) Morning Glory? (Remastered)"
      }
    ]
  },
  "albums": {
    "results": [
      {
        "title": "Familiar To Millions",
        "thumbnails": [...],
        "year": "2018",
        "browseId": "MPREb_AYetWMZunqA"
      }
    ],
    "browseId": "UCmMUZbaYdNH0bEd1PAlAqsA",
    "params": "6gPTAUNwc0JDbndLYlFBQV..."
  },
  "singles": {
    "results": [
      {
        "title": "Stand By Me (Mustique Demo)",
        "thumbnails": [...],
        "type": "Single",
        "year": "2016",
        "browseId": "MPREb_7MPKLhibN5G"
      }
    ],
    "browseId": "UCmMUZbaYdNH0bEd1PAlAqsA",
    "params": "6gPTAUNwc0JDbndLYlFBQV..."
  },
  "videos": {
    "results": [
      {
        "title": "Wonderwall",
        "thumbnails": [...],
        "views": "358M",
        "videoId": "bx1Bh8ZvH84",
        "playlistId": "PLMpM3Z0118S5xuNckw1HUcj1D021AnMEB"
      }
    ],
    "browseId": "VLPLMpM3Z0118S5xuNckw1HUcj1D021AnMEB"
  },
  "related": {
    "results": [
      {
        "browseId": "UCt2KxZpY5D__kapeQ8cauQw",
        "subscribers": "450K",
        "title": "The Verve"
      },
      {
        "browseId": "UCwK2Grm574W1u-sBzLikldQ",
        "subscribers": "341K",
        "title": "Liam Gallagher"
      },
      ...
    ]
  }
}

 The difference between description and descriptionRuns is that description is just the raw text of the description and does not have any knowledge of the hyperlinks in the description.
 Whereas descriptionRuns is a list of dictionaries which contains the text runs of the description that is aware of the hyperlinks in the description. There are two types of text runs.
   1. PlainText: which has format {"text": string}
   2. HyperLink: which has format {"text": string, "url": string}

Implementation

Future<JsonMap> getArtist(String channelId) async {
  final String cleanChannelId;
  if (channelId.startsWith('MPLA')) {
    cleanChannelId = channelId.substring(4);
  } else {
    cleanChannelId = channelId;
  }
  const endpoint = 'browse';
  final body = JsonMap.from({'browseId': cleanChannelId});
  final response = await sendRequest(endpoint, body);

  final results = List<JsonMap>.from(
    nav(response, SINGLE_COLUMN_TAB + SECTION_LIST) as List,
  );
  final header =
      JsonMap.from(
            response['header']! as JsonMap,
          )['musicImmersiveHeaderRenderer']
          as JsonMap? ??
      JsonMap.from(
            response['header']! as JsonMap,
          )['musicVisualHeaderRenderer']
          as JsonMap;
  final artist = <String, dynamic>{
    'name': nav(header, TITLE_TEXT),
    'description': null,
    'descriptionRuns': [],
    'views': null,
  };

  final descriptionShelf = findObjectByKey(
    results,
    DESCRIPTION_SHELF[0] as String,
    isKey: true,
  );

  if (descriptionShelf != null) {
    final parsedDescriptionRuns = parseDescriptionRuns(
      nav(descriptionShelf, DESCRIPTION_RUN_LIST),
    );
    final description = parsedDescriptionRuns.$1;
    final descriptionRuns = parsedDescriptionRuns.$2;
    artist['description'] = description;
    artist['descriptionRuns'] = descriptionRuns;
    artist['views'] =
        descriptionShelf.containsKey('subheader')
            ? (((descriptionShelf['subheader']! as JsonMap)['runs']!
                    as List)[0]
                as JsonMap)['text']
            : null;
  }

  final subscriptionButton =
      (header['subscriptionButton']! as JsonMap)['subscribeButtonRenderer']
          as JsonMap;
  artist['channelId'] = subscriptionButton['channelId'];
  artist['shuffleId'] = nav(header, [
    'playButton',
    'buttonRenderer',
    ...NAVIGATION_PLAYLIST_ID,
  ], nullIfAbsent: true);
  artist['radioId'] = nav(header, [
    'startRadioButton',
    'buttonRenderer',
    ...NAVIGATION_PLAYLIST_ID,
  ], nullIfAbsent: true);
  artist['subscribers'] = nav(subscriptionButton, [
    'subscriberCountText',
    'runs',
    0,
    'text',
  ], nullIfAbsent: true);
  artist['monthlyListeners'] = nav(header, [
    'monthlyListenerCount',
    'runs',
    0,
    'text',
  ], nullIfAbsent: true);
  artist['monthlyListeners'] = (artist['monthlyListeners'] as String?)
      ?.replaceAll(' monthly audience', '');
  artist['subscribed'] = subscriptionButton['subscribed'];
  artist['thumbnails'] = nav(header, THUMBNAILS, nullIfAbsent: true);
  artist['songs'] = JsonMap.from({'browseId': null});

  if (results.isNotEmpty && results[0].containsKey('musicShelfRenderer')) {
    // API sometimes does not return songs
    final musicShelf = nav(results[0], MUSIC_SHELF) as JsonMap;
    if ((nav(musicShelf, TITLE) as JsonMap).containsKey(
      'navigationEndpoint',
    )) {
      (artist['songs'] as JsonMap)['browseId'] = nav(
        musicShelf,
        TITLE + NAVIGATION_BROWSE_ID,
      );
    }
    (artist['songs'] as JsonMap)['results'] = parsePlaylistItems(
      List<JsonMap>.from(musicShelf['contents'] as List),
    );
  }

  artist.addAll(parser.parseChannelContents(results));
  return artist;
}