How to handle loading spotify playlists with > 100 items?

When loading music using the following query snippet, it only loads the first 100 songs of a spotify playlist. If i recall this is because the spotify api paginates. Does moonlink handle this pagination?
const result = await client.music.search({
query,
requester: message.author
});
const result = await client.music.search({
query,
requester: message.author
});
Thank you in advance!
Solution:
Not that Iโ€™m aware of
Jump to solution
46 Replies
1Lucas1.apk
1Lucas1.apkโ€ข2mo ago
GitHub
moonlink.js/src/typings/Interfaces.ts at v4 ยท Ecliptia/moonlink.js
MoonLink.js is a simple package for lavalink client, perfect for you to create your discord bot with songs, and very simple and easy to use. - Ecliptia/moonlink.js
1Lucas1.apk
1Lucas1.apkโ€ข2mo ago
If you are using source inside the package you have these limitation options But if it is lavasrc, there is no limitation on the client side, you must configure it on the server side, I don't know if there is a limitation, if not, in the next version I will provide these limitations But server will anyway load all tracks
MaxTechnics
MaxTechnicsOPโ€ข2mo ago
I've tried setting those earlier, however that didn't seem to impact anything. I'll try again with lower values to see if there are any limits. I'm not sure which spotify endpoint moonlink uses. When trying the following endpoint, the limit is 100 https://developer.spotify.com/documentation/web-api/reference/get-playlists-tracks setting the limit to 101 there throws an error
{
"error": {
"status": 400,
"message": "Invalid limit"
}
}
{
"error": {
"status": 400,
"message": "Invalid limit"
}
}
Just checked with the following configuration
options: {
spotify: {
clientId: client.config.spotifyClientID,
clientSecret: client.config.spotifyToken,
limitLoadPlaylist: 200,
limitLoadSearch: 200
}
}
options: {
spotify: {
clientId: client.config.spotifyClientID,
clientSecret: client.config.spotifyToken,
limitLoadPlaylist: 200,
limitLoadSearch: 200
}
}
It still only loads 100 tracks. Note i forgot to add in the previous message, i'm not using LavaSrc since i don't entirely know how to set it up (yet)
ComicallyBad
ComicallyBadโ€ข2mo ago
if you're running lavalink yourself, I can send an application.yml for LavaSrc and it's config not sure if there's much to configure though, there's an albumLoadLimit and playlistLoadLimit, not sure if there's a track limit this way. I believe I've queued playlists with 100+ songs, I can test it out
MaxTechnics
MaxTechnicsOPโ€ข2mo ago
I am self-hosting, and have a plugin installed being the youtube plugin.
MaxTechnics
MaxTechnicsOPโ€ข2mo ago
MaxTechnics
MaxTechnicsOPโ€ข2mo ago
I'll add the command structure here:
if (!LavaManager.nodeChecks(client, message)) return;
if (!vcChecks(message)) return;

// If there is an exising player and it is paused, resume instead
const existingPlayer = getPlayer(client, message);
if (existingPlayer && existingPlayer.paused) {
existingPlayer.resume();
return await message.react('๐Ÿ‘Œ');
}

if (!args[0]) {
const noQueryEmbed = new EmbedBuilder()
.setColor(tofuOrange)
.setDescription('To play a song, you need to specify which song you want to play!');

return message.channel.send({ embeds: [noQueryEmbed] });
}

let shouldSendQueuedEmbed = true;
const embed = new EmbedBuilder();
const query = args.slice(0).join(' ');

const player = existingPlayer ? existingPlayer : client.music.createPlayer({
guildId: message.guild.id,
voiceChannelId: message.member.voice.channel.id,
textChannelId: message.channel.id,
autoPlay: false
});

if (player.queue.tracks.length === 0) shouldSendQueuedEmbed = false; // if this is the first one we don't send queued message

player.connect({ setDeaf: true });

const result = await client.music.search({
query,
requester: message.author
});

musicLog(result);

if (!result.tracks.length) return message.reply('No results found!');

switch (result.loadType) {
case 'playlist':
shouldSendQueuedEmbed = true; // We do want to send play if more than 1 track is queued
player.queue.add(result.tracks);
musicLog('Youtube list given');
embed.setColor(tofuGreen);
embed.setDescription(`Queued ${result.tracks.length} tracks`);
break;
case 'track':
case 'search':
musicLog('Youtube track given');
// const [track] = results.tracks;
// tracks = [track];
const track = result.tracks[0];
player.queue.add(track);
embed.setColor(tofuGreen);
embed.setDescription(`Queued [${track.title}](${track.url}) [${message.author}]`);
break;
case 'empty':
musicLog('Nothing found');
embed.setColor(tofuError);
embed.setDescription('No matches found!');
break;
case 'error':
default:
console.log(result);
embed.setColor(tofuError);
embed.setDescription('Tofu choked :headstone:');
embed.setFooter({ text: 'Please try again later' });
embed.setTimestamp();
return;
}

if (!player.playing) player.play();
if (shouldSendQueuedEmbed) message.channel.send({ embeds: [embed] });
}
if (!LavaManager.nodeChecks(client, message)) return;
if (!vcChecks(message)) return;

// If there is an exising player and it is paused, resume instead
const existingPlayer = getPlayer(client, message);
if (existingPlayer && existingPlayer.paused) {
existingPlayer.resume();
return await message.react('๐Ÿ‘Œ');
}

if (!args[0]) {
const noQueryEmbed = new EmbedBuilder()
.setColor(tofuOrange)
.setDescription('To play a song, you need to specify which song you want to play!');

return message.channel.send({ embeds: [noQueryEmbed] });
}

let shouldSendQueuedEmbed = true;
const embed = new EmbedBuilder();
const query = args.slice(0).join(' ');

const player = existingPlayer ? existingPlayer : client.music.createPlayer({
guildId: message.guild.id,
voiceChannelId: message.member.voice.channel.id,
textChannelId: message.channel.id,
autoPlay: false
});

if (player.queue.tracks.length === 0) shouldSendQueuedEmbed = false; // if this is the first one we don't send queued message

player.connect({ setDeaf: true });

const result = await client.music.search({
query,
requester: message.author
});

musicLog(result);

if (!result.tracks.length) return message.reply('No results found!');

switch (result.loadType) {
case 'playlist':
shouldSendQueuedEmbed = true; // We do want to send play if more than 1 track is queued
player.queue.add(result.tracks);
musicLog('Youtube list given');
embed.setColor(tofuGreen);
embed.setDescription(`Queued ${result.tracks.length} tracks`);
break;
case 'track':
case 'search':
musicLog('Youtube track given');
// const [track] = results.tracks;
// tracks = [track];
const track = result.tracks[0];
player.queue.add(track);
embed.setColor(tofuGreen);
embed.setDescription(`Queued [${track.title}](${track.url}) [${message.author}]`);
break;
case 'empty':
musicLog('Nothing found');
embed.setColor(tofuError);
embed.setDescription('No matches found!');
break;
case 'error':
default:
console.log(result);
embed.setColor(tofuError);
embed.setDescription('Tofu choked :headstone:');
embed.setFooter({ text: 'Please try again later' });
embed.setTimestamp();
return;
}

if (!player.playing) player.play();
if (shouldSendQueuedEmbed) message.channel.send({ embeds: [embed] });
}
However it is 4am here at this point, so will likely be signing off soon. From what i've understood when using LavaSrc, you also need to query differently, or am I wrong there?
MEE6
MEE6โ€ข2mo ago
GG @MaxTechnics, you just advanced to level 1!
ComicallyBad
ComicallyBadโ€ข2mo ago
it should be the same, as spotify isn't actually used to play songs though, they will all be queued through another source
ComicallyBad
ComicallyBadโ€ข2mo ago
it did queue fine for me
No description
MaxTechnics
MaxTechnicsOPโ€ข2mo ago
I am aware that spotify streams are impossible. But it matches (most often with youtube) instead Perhaps its a limitation in the default matching algorithm, maybe it does not handle the pagination?
ComicallyBad
ComicallyBadโ€ข2mo ago
possibly, with LavaSrc though it seems to handle fine. So it may be worth trying. I don't believe you'd have to change any of your code either I also am using a spotify clientID & clientSecret, so that could be why I don't have issues
MaxTechnics
MaxTechnicsOPโ€ข2mo ago
So am i, though not on the lavalink side
MaxTechnics
MaxTechnicsOPโ€ข2mo ago
Thank you for the pointers and setup! I'll be looking into it first thing tomorrow. and will get back to the post here
ComicallyBad
ComicallyBadโ€ข2mo ago
yeah no problem, I'm guessing you may be right, could be an issue with the pagination currently
MaxTechnics
MaxTechnicsOPโ€ข2mo ago
Last I worked directly with the Spotify api was in 2021 (trying to actually pull audio from their service, which of course was impossible). Which led me to believe the 100 song limit was pagination related. I did expect it to error when setting the Moonlink Manger config to invalid limits (like 100+), maybe there are some protections against it?
ComicallyBad
ComicallyBadโ€ข2mo ago
I haven't done much with the spotify api directly, I'd have to test it out. I can try to see if there are any limits though
MaxTechnics
MaxTechnicsOPโ€ข2mo ago
The link in my first post to the docs has a built in little playground to interact with the api
ComicallyBad
ComicallyBadโ€ข2mo ago
huh, I see what you mean yeah, the direct API call cuts off at 100 exactly
MaxTechnics
MaxTechnicsOPโ€ข2mo ago
I've tried the application.yml you provided. I got all the tokens put in, however the player still only loads 100 tracks. I'll be looking into some docs to see if code modifications are required
!_SREERAJ_SK
!_SREERAJ_SKโ€ข2mo ago
Code your own spotify playlist fetcher and use it to get playlist data , then send the info to lavalink..
!_SREERAJ_SK
!_SREERAJ_SKโ€ข2mo ago
this works ig
MaxTechnics
MaxTechnicsOPโ€ข2mo ago
That would work, though isn't it better to implement the pagination in moonlink itself? I'll try it later today
!_SREERAJ_SK
!_SREERAJ_SKโ€ข2mo ago
this way you can save your playlist too soo no need to get link everytime.. idk if its possible with moonlink/lavalink
MaxTechnics
MaxTechnicsOPโ€ข2mo ago
I know moonlink supports database storage, though haven't looked into that myself either
MEE6
MEE6โ€ข2mo ago
GG @MaxTechnics, you just advanced to level 2!
!_SREERAJ_SK
!_SREERAJ_SKโ€ข2mo ago
oh i didn't know that... i use this setup no issues so far.. tested with playlist having 1k+ songs works fine
MaxTechnics
MaxTechnicsOPโ€ข2mo ago
I tried it and it does in fact work, Though it would be cool to see this handling in moonlink itself.
!_SREERAJ_SK
!_SREERAJ_SKโ€ข2mo ago
btw is there any limit to how many songs i can queue ??
MaxTechnics
MaxTechnicsOPโ€ข2mo ago
I don't think so, as long as you respect api ratelimits
!_SREERAJ_SK
!_SREERAJ_SKโ€ข2mo ago
hmm i use custom queue in my bot .. planning to switch to inbuilt queue
MaxTechnics
MaxTechnicsOPโ€ข2mo ago
i am currently migrating to moonlink from lavaclient And trying to recreate the feel of groovy bot
1Lucas1.apk
1Lucas1.apkโ€ข2mo ago
No description
1Lucas1.apk
1Lucas1.apkโ€ข2mo ago
what I find strangest It's because it's not splitting.
MaxTechnics
MaxTechnicsOPโ€ข2mo ago
I took a quick look at the source in moonlink, it does not seem to have any pagination logic.
How do you query the playlist in your bot? The standard manager.search does not fix the 100song issue. Im suspecting it does not make use of lavasrc
1Lucas1.apk
1Lucas1.apkโ€ข2mo ago
I don't use it, and there is logic, when the songs are searched, it does a split of 0, the limit defined in all that loads as playlists in spotify, I just reinforced to do a global
MaxTechnics
MaxTechnicsOPโ€ข2mo ago
I see, wouldn't it make sense to have pagination on the endpoints that do that though? Not sure how the other endpoints differ
1Lucas1.apk
1Lucas1.apkโ€ข2mo ago
Yes, the Spotify endpoint delivers per page This logic is a bit strange indeed. But I'll do it by track, for me it's better than counting Spotify pages without understanding correctly
MaxTechnics
MaxTechnicsOPโ€ข2mo ago
I think the api endpoint's response has all that info included, as well as the url for the next page
MaxTechnics
MaxTechnicsOPโ€ข2mo ago
next and previous are endpoint urls for next pages. I don't think it'd be too complicated to check if (next) Loadfrompage(next)
No description
1Lucas1.apk
1Lucas1.apkโ€ข2mo ago
Now I understand, I'll commit and correct it
MaxTechnics
MaxTechnicsOPโ€ข2mo ago
If you'd like i can test before you release
Solution
ComicallyBad
ComicallyBadโ€ข2mo ago
Not that Iโ€™m aware of
MaxTechnics
MaxTechnicsOPโ€ข2mo ago
Just switched back to release, and can confirm that loading now works as expected. So for those reading, make sure to update to https://github.com/Ecliptia/moonlink.js/releases/tag/v4.60.4 or later. To all here, thank you very much for your help and the quick update!
GitHub
Release v4.60.4 ยท Ecliptia/moonlink.js
What's Changed Add qodana CI checks by @qodana-cloud[bot] in #162 sync: v4 with dev by @1Lucas1apk in #163 sync: v4 with dev by @1Lucas1apk in #164 Full Changelog: v4.52.2...v4.60.4 โœจ New Fea...

Did you find this page helpful?