parseSearchResult function

JsonMap parseSearchResult(
  1. JsonMap data,
  2. String? resultType,
  3. String? category
)

Parses a search result from data.

Implementation

JsonMap parseSearchResult(JsonMap data, String? resultType, String? category) {
  final defaultOffset = ((resultType == null || resultType == 'album') ? 2 : 0);
  final searchResult = <String, dynamic>{'category': category};

  final videoType = nav(data, [
    ...PLAY_BUTTON,
    'playNavigationEndpoint',
    ...NAVIGATION_VIDEO_TYPE,
  ], nullIfAbsent: true);

  final String realResultType;
  // Determine result type based on browseId
  if (resultType == null) {
    final browseId =
        nav(data, NAVIGATION_BROWSE_ID, nullIfAbsent: true) as String?;
    if (browseId != null) {
      final mapping = {
        'VM': 'playlist',
        'RD': 'playlist',
        'VL': 'playlist',
        'MPLA': 'artist',
        'MPRE': 'album',
        'MPSP': 'podcast',
        'MPED': 'episode',
        'UC': 'artist',
      };
      realResultType =
          mapping.entries
              .firstWhere(
                (e) => browseId.startsWith(e.key),
                orElse: () => const MapEntry('', ''),
              )
              .value;
    } else {
      realResultType =
          {
            'MUSIC_VIDEO_TYPE_ATV': 'song',
            'MUSIC_VIDEO_TYPE_PODCAST_EPISODE': 'episode',
          }[videoType ?? ''] ??
          'video';
    }
  } else {
    realResultType = resultType;
  }

  searchResult['resultType'] = realResultType;

  if (realResultType != 'artist') searchResult['title'] = getItemText(data, 0);

  if (realResultType == 'artist') {
    searchResult['artist'] = getItemText(data, 0);
    parseMenuPlaylists(data, searchResult);
  } else if (realResultType == 'album') {
    searchResult['type'] = getItemText(data, 1);
    final playNavigation = nav(data, [
      ...PLAY_BUTTON,
      'playNavigationEndpoint',
    ], nullIfAbsent: true);
    searchResult['playlistId'] = parseAlbumPlaylistIdIfExists(
      playNavigation as JsonMap?,
    );
  } else if (realResultType == 'playlist') {
    final flexItem = nav(getFlexColumnItem(data, 1), TEXT_RUNS) as List;
    final hasAuthor = flexItem.length == defaultOffset + 3;
    searchResult['itemCount'] =
        (getItemText(data, 1, runIndex: defaultOffset + (hasAuthor ? 2 : 0)) ??
                '')
            .split(' ')[0];
    if (searchResult['itemCount'] != null &&
        (num.tryParse(searchResult['itemCount'] as String) != null)) {
      searchResult['itemCount'] = toInt(searchResult['itemCount'] as String);
    }
    searchResult['author'] =
        hasAuthor ? getItemText(data, 1, runIndex: defaultOffset) : null;
  } else if (realResultType == 'station') {
    searchResult['videoId'] = nav(data, NAVIGATION_VIDEO_ID);
    searchResult['playlistId'] = nav(data, NAVIGATION_PLAYLIST_ID);
  } else if (realResultType == 'profile') {
    searchResult['name'] = getItemText(
      data,
      1,
      runIndex: 2,
      noneIfAbsent: true,
    );
  } else if (realResultType == 'song') {
    searchResult['album'] = null;
    if (data.containsKey('menu')) {
      final toggleMenu = findObjectByKey(
        nav(data, MENU_ITEMS) as List,
        TOGGLE_MENU,
      );
      if (toggleMenu != null) {
        searchResult['inLibrary'] = parseSongLibraryStatus(toggleMenu);
        searchResult['feedbackTokens'] = parseSongMenuTokens(toggleMenu);
      }
    }
  } else if (realResultType == 'upload') {
    final browseId = nav(data, NAVIGATION_BROWSE_ID, nullIfAbsent: true);
    if (browseId == null) {
      final flexItems = [
        nav(getFlexColumnItem(data, 0), ['text', 'runs'], nullIfAbsent: true),
        nav(getFlexColumnItem(data, 1), ['text', 'runs'], nullIfAbsent: true),
      ];
      if (flexItems[0] != null) {
        searchResult['videoId'] = nav(
          (flexItems[0] as List)[0],
          NAVIGATION_VIDEO_ID,
          nullIfAbsent: true,
        );
        searchResult['playlistId'] = nav(
          (flexItems[0] as List)[0],
          NAVIGATION_PLAYLIST_ID,
          nullIfAbsent: true,
        );
      }
      if (flexItems[1] != null) {
        searchResult.addAll(parseSongRuns(flexItems[1] as List));
      }
      searchResult['resultType'] = 'song';
    } else {
      searchResult['browseId'] = browseId;
      if ((searchResult['browseId'] as String).contains('artist')) {
        searchResult['resultType'] = 'artist';
      } else {
        final flexItem2 = getFlexColumnItem(data, 1);
        final runs =
            flexItem2 != null
                ? List.generate(
                  ((flexItem2['text'] as JsonMap)['runs'] as List).length,
                  (i) {
                    final run =
                        ((flexItem2['text'] as JsonMap)['runs'] as List)[i];
                    return i.isEven ? (run as JsonMap)['text'] : null;
                  },
                ).whereType<String>().toList()
                : <String>[];
        if (runs.length > 1) searchResult['artist'] = runs[1];
        if (runs.length > 2) searchResult['releaseDate'] = runs[2];
        searchResult['resultType'] = 'album';
      }
    }
  }

  if (['song', 'video', 'episode'].contains(realResultType)) {
    searchResult['videoId'] = nav(data, [
      ...PLAY_BUTTON,
      'playNavigationEndpoint',
      'watchEndpoint',
      'videoId',
    ], nullIfAbsent: true);
    searchResult['videoType'] = videoType;
  }

  if (['song', 'video', 'album'].contains(realResultType)) {
    searchResult['duration'] = null;
    searchResult['year'] = null;
    final flexItem = getFlexColumnItem(data, 1);
    final runs = (flexItem!['text'] as JsonMap)['runs'] as List;
    final flexItem2 = getFlexColumnItem(data, 2);
    if (flexItem2 != null) {
      runs.addAll([
        {'text': ''},
        ...(flexItem2['text'] as JsonMap)['runs'] as Iterable,
      ]);
    }
    final songInfo = parseSongRuns(runs, skipTypeSpec: true);
    searchResult.addAll(songInfo);
  }

  if ([
    'artist',
    'album',
    'playlist',
    'profile',
    'podcast',
  ].contains(realResultType)) {
    searchResult['browseId'] = nav(
      data,
      NAVIGATION_BROWSE_ID,
      nullIfAbsent: true,
    );
  }

  if (['song', 'album'].contains(realResultType)) {
    searchResult['isExplicit'] =
        nav(data, BADGE_LABEL, nullIfAbsent: true) != null;
  }

  if (realResultType == 'episode') {
    final flexItem = getFlexColumnItem(data, 1);
    final runs = (nav(flexItem, TEXT_RUNS) as List).sublist(defaultOffset);
    final hasDate = runs.length > 1 ? 1 : 0;
    searchResult['live'] =
        nav(data, ['badges', 0, 'liveBadgeRenderer'], nullIfAbsent: true) !=
        null;
    if (hasDate > 0) searchResult['date'] = (runs[0] as JsonMap)['text'];
    searchResult['podcast'] = parseIdName(runs[hasDate * 2] as JsonMap?);
  }

  searchResult['thumbnails'] = nav(data, THUMBNAILS, nullIfAbsent: true);
  return searchResult;
}