aboutsummaryrefslogtreecommitdiff
path: root/src/utils/get-youtube-and-spotify-suggestions-for.ts
blob: bd6f1c87bd2ceddca2dd4a4fbdd01928993f3b5a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
import {APIApplicationCommandOptionChoice} from 'discord-api-types/v10';
import SpotifyWebApi from 'spotify-web-api-node';
import getYouTubeSuggestionsFor from './get-youtube-suggestions-for.js';

const filterDuplicates = <T extends {name: string}>(items: T[]) => {
  const results: T[] = [];

  for (const item of items) {
    if (!results.some(result => result.name === item.name)) {
      results.push(item);
    }
  }

  return results;
};

const getYouTubeAndSpotifySuggestionsFor = async (query: string, spotify?: SpotifyWebApi, limit = 10): Promise<APIApplicationCommandOptionChoice[]> => {
  // Only search Spotify if enabled
  const spotifySuggestionPromise = spotify === undefined
    ? undefined
    : spotify.search(query, ['album', 'track'], {limit});

  const youtubeSuggestions = await getYouTubeSuggestionsFor(query);

  const totalYouTubeResults = youtubeSuggestions.length;
  const numOfYouTubeSuggestions = Math.min(limit, totalYouTubeResults);

  let suggestions: APIApplicationCommandOptionChoice[] = [];

  suggestions.push(
    ...youtubeSuggestions
      .slice(0, numOfYouTubeSuggestions)
      .map(suggestion => ({
        name: `YouTube: ${suggestion}`,
        value: suggestion,
      }),
      ));

  if (spotify !== undefined && spotifySuggestionPromise !== undefined) {
    const spotifyResponse = (await spotifySuggestionPromise).body;
    const spotifyAlbums = filterDuplicates(spotifyResponse.albums?.items ?? []);
    const spotifyTracks = filterDuplicates(spotifyResponse.tracks?.items ?? []);

    const totalSpotifyResults = spotifyAlbums.length + spotifyTracks.length;

    // Number of results for each source should be roughly the same.
    // If we don't have enough Spotify suggestions, prioritize YouTube results.
    const maxSpotifySuggestions = Math.floor(limit / 2);
    const numOfSpotifySuggestions = Math.min(maxSpotifySuggestions, totalSpotifyResults);

    const maxSpotifyAlbums = Math.floor(numOfSpotifySuggestions / 2);
    const numOfSpotifyAlbums = Math.min(maxSpotifyAlbums, spotifyResponse.albums?.items.length ?? 0);
    const maxSpotifyTracks = numOfSpotifySuggestions - numOfSpotifyAlbums;

    // Make room for spotify results
    const maxYouTubeSuggestions = limit - numOfSpotifySuggestions;
    suggestions = suggestions.slice(0, maxYouTubeSuggestions);

    suggestions.push(
      ...spotifyAlbums.slice(0, maxSpotifyAlbums).map(album => ({
        name: `Spotify: 💿 ${album.name}${album.artists.length > 0 ? ` - ${album.artists[0].name}` : ''}`,
        value: `spotify:album:${album.id}`,
      })),
    );

    suggestions.push(
      ...spotifyTracks.slice(0, maxSpotifyTracks).map(track => ({
        name: `Spotify: 🎵 ${track.name}${track.artists.length > 0 ? ` - ${track.artists[0].name}` : ''}`,
        value: `spotify:track:${track.id}`,
      })),
    );
  }

  return suggestions;
};

export default getYouTubeAndSpotifySuggestionsFor;