async search(artists, track, album, duration) {
    [artists, track, album, duration] = _getSearchArgs(artists, track, album, duration);

    const strippedArtists = textUtils.stripText(artists);
    const strippedMeta = [...textUtils.stripText(track.split(' ')), ...strippedArtists];
    let searchResults = await Promise.all(
      (
        await this.#store.searchQueue.push([
          [strippedMeta, ['Official Audio']],
          [strippedMeta, ['Audio']],
          [strippedMeta, ['Lyrics']],
          [strippedMeta, []],
        ])
      ).map(result => Promise.resolve(result).reflect()),
    );
    if (searchResults.every(result => result.isRejected())) {
      const err = searchResults[searchResults.length - 1].reason();
      throw new YouTubeSearchError(err.message, null, err.code);
    }
    searchResults = searchResults.map(ret => (ret.isFulfilled() ? ret.value() : {}));
    const highestViews = Math.max(...searchResults.map(sources => sources.highestViews));
    function calculateAccuracyFor(item) {
      let accuracy = 0;
      // get weighted delta from expected duration
      accuracy += 100 - (duration ? Math.abs(duration - item.duration.seconds * 1000) / duration : 0.5) * 100;
      // bump accuracy by max of 80% on the basis of highest views
      accuracy += (cur => cur * (80 / 100) * (item.views / highestViews))(100 - accuracy);
      // bump accuracy by 60% if video author matches track author
      accuracy += (cur =>
        textUtils.getWeight(strippedArtists, textUtils.stripText([item.author.name])) >= 80 ? (60 / 100) * cur : 0)(
        100 - accuracy,
      );
      return accuracy;
    }
    const final = {};
    searchResults.forEach(source => {
      if (Array.isArray(source.results))
        source.results.forEach(item => {
          // prune duplicates
          if (item && 'videoId' in item && !(item.videoId in final))
            final[item.videoId] = {
              title: item.title,
              type: item.type,
              author: item.author.name,
              duration: item.duration.timestamp,
              duration_ms: item.duration.seconds * 1000,
              videoId: item.videoId,
              xFilters: source.xFilters,
              accuracy: calculateAccuracyFor(item),
              getFeeds: genAsyncGetFeedsFn(item.videoId),
            };
        });
    });
    return Object.values(final).sort((a, b) => (a.accuracy > b.accuracy ? -1 : 1));
  }
Search YouTube service for matches
@param {string|string[]} [artists] An artist or list of artists
@param {string} [track] Track name
@param {number} [duration] Duration in milliseconds

If `track` is a number, it becomes duration, leaving `track` undefined.
If `album` is a number, it becomes duration, leaving `album` undefined.
If `artists` is a string and `track` is undefined, it becomes `track`, leaving artists empty.
If `artists` is non-array but `track` is defined, artists becomes an item in the artists array.

@returns {YouTubeSearchResult} YouTubeSearchResults