From 296a0a8178fb3c670c924b230a042cc1e6241719 Mon Sep 17 00:00:00 2001 From: Thongrapee Panyapatiphan Date: Thu, 30 Sep 2021 23:55:21 +0700 Subject: [PATCH 01/10] Add config for song limit per playlist --- src/commands/play.ts | 15 +++++++++++---- src/services/config.ts | 11 +++++++++++ src/services/get-songs.ts | 16 +++++++++------- 3 files changed, 31 insertions(+), 11 deletions(-) diff --git a/src/commands/play.ts b/src/commands/play.ts index a907a40..81a4ae1 100644 --- a/src/commands/play.ts +++ b/src/commands/play.ts @@ -10,6 +10,7 @@ import LoadingMessage from '../utils/loading-message.js'; import errorMsg from '../utils/error-msg.js'; import Command from '.'; import GetSongs from '../services/get-songs.js'; +import Config from '../services/config.js'; @injectable() export default class implements Command { @@ -31,10 +32,16 @@ export default class implements Command { private readonly playerManager: PlayerManager; private readonly getSongs: GetSongs; + private readonly playlistLimit: number; - constructor(@inject(TYPES.Managers.Player) playerManager: PlayerManager, @inject(TYPES.Services.GetSongs) getSongs: GetSongs) { + constructor( + @inject(TYPES.Managers.Player) playerManager: PlayerManager, + @inject(TYPES.Services.GetSongs) getSongs: GetSongs, + @inject(TYPES.Config) config: Config, + ) { this.playerManager = playerManager; this.getSongs = getSongs; + this.playlistLimit = config.getPlaylistLimit(); } public async execute(msg: Message, args: string[]): Promise { @@ -103,11 +110,11 @@ export default class implements Command { } else if (url.protocol === 'spotify:' || url.host === 'open.spotify.com') { const [convertedSongs, nSongsNotFound, totalSongs] = await this.getSongs.spotifySource(args[0]); - if (totalSongs > 50) { - extraMsg = 'a random sample of 50 songs was taken'; + if (totalSongs > this.playlistLimit) { + extraMsg = `a random sample of ${this.playlistLimit} songs was taken`; } - if (totalSongs > 50 && nSongsNotFound !== 0) { + if (totalSongs > this.playlistLimit && nSongsNotFound !== 0) { extraMsg += ' and '; } diff --git a/src/services/config.ts b/src/services/config.ts index 759a27a3..087ea0b 100644 --- a/src/services/config.ts +++ b/src/services/config.ts @@ -4,6 +4,7 @@ import path from 'path'; dotenv.config(); export const DATA_DIR = path.resolve(process.env.DATA_DIR ? process.env.DATA_DIR : './data'); +const DEFAULT_PLAYLIST_LIMIT = 50; const CONFIG_MAP = { DISCORD_TOKEN: process.env.DISCORD_TOKEN, @@ -12,6 +13,7 @@ const CONFIG_MAP = { SPOTIFY_CLIENT_SECRET: process.env.SPOTIFY_CLIENT_SECRET, DATA_DIR, CACHE_DIR: path.join(DATA_DIR, 'cache'), + PLAYLIST_LIMIT: process.env.PLAYLIST_LIMIT, } as const; @injectable() @@ -22,6 +24,7 @@ export default class Config { readonly SPOTIFY_CLIENT_SECRET!: string; readonly DATA_DIR!: string; readonly CACHE_DIR!: string; + readonly PLAYLIST_LIMIT!: string; constructor() { for (const [key, value] of Object.entries(CONFIG_MAP)) { @@ -33,4 +36,12 @@ export default class Config { this[key as keyof typeof CONFIG_MAP] = value; } } + + getPlaylistLimit() { + if (!this.PLAYLIST_LIMIT) { + return DEFAULT_PLAYLIST_LIMIT; + } + + return Number(this.PLAYLIST_LIMIT) || DEFAULT_PLAYLIST_LIMIT; + } } diff --git a/src/services/get-songs.ts b/src/services/get-songs.ts index ba4401c..dcf6823 100644 --- a/src/services/get-songs.ts +++ b/src/services/get-songs.ts @@ -27,6 +27,7 @@ export default class { private readonly youtubeKey: string; private readonly spotify: Spotify; private readonly cache: CacheProvider; + private readonly playlistLimit: number; private readonly ytsrQueue: PQueue; @@ -38,6 +39,7 @@ export default class { this.youtubeKey = config.YOUTUBE_API_KEY; this.spotify = thirdParty.spotify; this.cache = cache; + this.playlistLimit = config.getPlaylistLimit(); this.ytsrQueue = new PQueue({concurrency: 4}); } @@ -126,7 +128,7 @@ export default class { const {items, nextPageToken} = await this.cache.wrap( this.youtube.playlists.items, listId, - {maxResults: '50', pageToken: nextToken}, + {maxResults: `${this.playlistLimit}`, pageToken: nextToken}, { expiresIn: ONE_MINUTE_IN_SECONDS, }, @@ -199,7 +201,7 @@ export default class { case 'album': { const uri = parsed as spotifyURI.Album; - const [{body: album}, {body: {items}}] = await Promise.all([this.spotify.getAlbum(uri.id), this.spotify.getAlbumTracks(uri.id, {limit: 50})]); + const [{body: album}, {body: {items}}] = await Promise.all([this.spotify.getAlbum(uri.id), this.spotify.getAlbumTracks(uri.id, {limit: this.playlistLimit})]); tracks.push(...items); @@ -210,7 +212,7 @@ export default class { case 'playlist': { const uri = parsed as spotifyURI.Playlist; - let [{body: playlistResponse}, {body: tracksResponse}] = await Promise.all([this.spotify.getPlaylist(uri.id), this.spotify.getPlaylistTracks(uri.id, {limit: 50})]); + let [{body: playlistResponse}, {body: tracksResponse}] = await Promise.all([this.spotify.getPlaylist(uri.id), this.spotify.getPlaylistTracks(uri.id, {limit: this.playlistLimit})]); playlist = {title: playlistResponse.name, source: playlistResponse.href}; @@ -219,7 +221,7 @@ export default class { while (tracksResponse.next) { // eslint-disable-next-line no-await-in-loop ({body: tracksResponse} = await this.spotify.getPlaylistTracks(uri.id, { - limit: parseInt(new URL(tracksResponse.next).searchParams.get('limit') ?? '50', 10), + limit: parseInt(new URL(tracksResponse.next).searchParams.get('limit') ?? `${this.playlistLimit}`, 10), offset: parseInt(new URL(tracksResponse.next).searchParams.get('offset') ?? '0', 10), })); @@ -252,13 +254,13 @@ export default class { } } - // Get 50 random songs if many + // Get random songs if many then limit to playlistLimit (defaults to 50) const originalNSongs = tracks.length; - if (tracks.length > 50) { + if (tracks.length > this.playlistLimit) { const shuffled = shuffle(tracks); - tracks = shuffled.slice(0, 50); + tracks = shuffled.slice(0, this.playlistLimit); } let songs = await Promise.all(tracks.map(async track => this.spotifyToYouTube(track, playlist))); From 96dcc4a5364d934b413b247e7b69ff31606c6183 Mon Sep 17 00:00:00 2001 From: Thongrapee Panyapatiphan Date: Fri, 1 Oct 2021 20:48:32 +0700 Subject: [PATCH 02/10] Revert "Add config for song limit per playlist" This reverts commit 296a0a8178fb3c670c924b230a042cc1e6241719. --- src/commands/play.ts | 15 ++++----------- src/services/config.ts | 11 ----------- src/services/get-songs.ts | 16 +++++++--------- 3 files changed, 11 insertions(+), 31 deletions(-) diff --git a/src/commands/play.ts b/src/commands/play.ts index 81a4ae1..a907a40 100644 --- a/src/commands/play.ts +++ b/src/commands/play.ts @@ -10,7 +10,6 @@ import LoadingMessage from '../utils/loading-message.js'; import errorMsg from '../utils/error-msg.js'; import Command from '.'; import GetSongs from '../services/get-songs.js'; -import Config from '../services/config.js'; @injectable() export default class implements Command { @@ -32,16 +31,10 @@ export default class implements Command { private readonly playerManager: PlayerManager; private readonly getSongs: GetSongs; - private readonly playlistLimit: number; - constructor( - @inject(TYPES.Managers.Player) playerManager: PlayerManager, - @inject(TYPES.Services.GetSongs) getSongs: GetSongs, - @inject(TYPES.Config) config: Config, - ) { + constructor(@inject(TYPES.Managers.Player) playerManager: PlayerManager, @inject(TYPES.Services.GetSongs) getSongs: GetSongs) { this.playerManager = playerManager; this.getSongs = getSongs; - this.playlistLimit = config.getPlaylistLimit(); } public async execute(msg: Message, args: string[]): Promise { @@ -110,11 +103,11 @@ export default class implements Command { } else if (url.protocol === 'spotify:' || url.host === 'open.spotify.com') { const [convertedSongs, nSongsNotFound, totalSongs] = await this.getSongs.spotifySource(args[0]); - if (totalSongs > this.playlistLimit) { - extraMsg = `a random sample of ${this.playlistLimit} songs was taken`; + if (totalSongs > 50) { + extraMsg = 'a random sample of 50 songs was taken'; } - if (totalSongs > this.playlistLimit && nSongsNotFound !== 0) { + if (totalSongs > 50 && nSongsNotFound !== 0) { extraMsg += ' and '; } diff --git a/src/services/config.ts b/src/services/config.ts index 087ea0b..759a27a3 100644 --- a/src/services/config.ts +++ b/src/services/config.ts @@ -4,7 +4,6 @@ import path from 'path'; dotenv.config(); export const DATA_DIR = path.resolve(process.env.DATA_DIR ? process.env.DATA_DIR : './data'); -const DEFAULT_PLAYLIST_LIMIT = 50; const CONFIG_MAP = { DISCORD_TOKEN: process.env.DISCORD_TOKEN, @@ -13,7 +12,6 @@ const CONFIG_MAP = { SPOTIFY_CLIENT_SECRET: process.env.SPOTIFY_CLIENT_SECRET, DATA_DIR, CACHE_DIR: path.join(DATA_DIR, 'cache'), - PLAYLIST_LIMIT: process.env.PLAYLIST_LIMIT, } as const; @injectable() @@ -24,7 +22,6 @@ export default class Config { readonly SPOTIFY_CLIENT_SECRET!: string; readonly DATA_DIR!: string; readonly CACHE_DIR!: string; - readonly PLAYLIST_LIMIT!: string; constructor() { for (const [key, value] of Object.entries(CONFIG_MAP)) { @@ -36,12 +33,4 @@ export default class Config { this[key as keyof typeof CONFIG_MAP] = value; } } - - getPlaylistLimit() { - if (!this.PLAYLIST_LIMIT) { - return DEFAULT_PLAYLIST_LIMIT; - } - - return Number(this.PLAYLIST_LIMIT) || DEFAULT_PLAYLIST_LIMIT; - } } diff --git a/src/services/get-songs.ts b/src/services/get-songs.ts index dcf6823..ba4401c 100644 --- a/src/services/get-songs.ts +++ b/src/services/get-songs.ts @@ -27,7 +27,6 @@ export default class { private readonly youtubeKey: string; private readonly spotify: Spotify; private readonly cache: CacheProvider; - private readonly playlistLimit: number; private readonly ytsrQueue: PQueue; @@ -39,7 +38,6 @@ export default class { this.youtubeKey = config.YOUTUBE_API_KEY; this.spotify = thirdParty.spotify; this.cache = cache; - this.playlistLimit = config.getPlaylistLimit(); this.ytsrQueue = new PQueue({concurrency: 4}); } @@ -128,7 +126,7 @@ export default class { const {items, nextPageToken} = await this.cache.wrap( this.youtube.playlists.items, listId, - {maxResults: `${this.playlistLimit}`, pageToken: nextToken}, + {maxResults: '50', pageToken: nextToken}, { expiresIn: ONE_MINUTE_IN_SECONDS, }, @@ -201,7 +199,7 @@ export default class { case 'album': { const uri = parsed as spotifyURI.Album; - const [{body: album}, {body: {items}}] = await Promise.all([this.spotify.getAlbum(uri.id), this.spotify.getAlbumTracks(uri.id, {limit: this.playlistLimit})]); + const [{body: album}, {body: {items}}] = await Promise.all([this.spotify.getAlbum(uri.id), this.spotify.getAlbumTracks(uri.id, {limit: 50})]); tracks.push(...items); @@ -212,7 +210,7 @@ export default class { case 'playlist': { const uri = parsed as spotifyURI.Playlist; - let [{body: playlistResponse}, {body: tracksResponse}] = await Promise.all([this.spotify.getPlaylist(uri.id), this.spotify.getPlaylistTracks(uri.id, {limit: this.playlistLimit})]); + let [{body: playlistResponse}, {body: tracksResponse}] = await Promise.all([this.spotify.getPlaylist(uri.id), this.spotify.getPlaylistTracks(uri.id, {limit: 50})]); playlist = {title: playlistResponse.name, source: playlistResponse.href}; @@ -221,7 +219,7 @@ export default class { while (tracksResponse.next) { // eslint-disable-next-line no-await-in-loop ({body: tracksResponse} = await this.spotify.getPlaylistTracks(uri.id, { - limit: parseInt(new URL(tracksResponse.next).searchParams.get('limit') ?? `${this.playlistLimit}`, 10), + limit: parseInt(new URL(tracksResponse.next).searchParams.get('limit') ?? '50', 10), offset: parseInt(new URL(tracksResponse.next).searchParams.get('offset') ?? '0', 10), })); @@ -254,13 +252,13 @@ export default class { } } - // Get random songs if many then limit to playlistLimit (defaults to 50) + // Get 50 random songs if many const originalNSongs = tracks.length; - if (tracks.length > this.playlistLimit) { + if (tracks.length > 50) { const shuffled = shuffle(tracks); - tracks = shuffled.slice(0, this.playlistLimit); + tracks = shuffled.slice(0, 50); } let songs = await Promise.all(tracks.map(async track => this.spotifyToYouTube(track, playlist))); From c9cc9a17b13f45786222db948e746b5f8c3742e2 Mon Sep 17 00:00:00 2001 From: Thongrapee Panyapatiphan Date: Fri, 1 Oct 2021 21:11:43 +0700 Subject: [PATCH 03/10] Read playlist song limit from Settings --- src/commands/play.ts | 19 ++++++++++++++----- src/models/settings.ts | 4 ++++ src/services/get-songs.ts | 18 +++++++++--------- 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/src/commands/play.ts b/src/commands/play.ts index a907a40..fce051f 100644 --- a/src/commands/play.ts +++ b/src/commands/play.ts @@ -1,3 +1,4 @@ +/* eslint-disable complexity */ import {TextChannel, Message} from 'discord.js'; import {URL} from 'url'; import {Except} from 'type-fest'; @@ -10,6 +11,7 @@ import LoadingMessage from '../utils/loading-message.js'; import errorMsg from '../utils/error-msg.js'; import Command from '.'; import GetSongs from '../services/get-songs.js'; +import Settings from '../models/settings.js'; @injectable() export default class implements Command { @@ -39,6 +41,7 @@ export default class implements Command { public async execute(msg: Message, args: string[]): Promise { const [targetVoiceChannel] = getMemberVoiceChannel(msg.member!) ?? getMostPopularVoiceChannel(msg.guild!); + const playlistLimit = await this.getPlaylistLimit(msg.guild!.id); const res = new LoadingMessage(msg.channel as TextChannel); await res.start(); @@ -88,7 +91,8 @@ export default class implements Command { // YouTube source if (url.searchParams.get('list')) { // YouTube playlist - newSongs.push(...await this.getSongs.youtubePlaylist(url.searchParams.get('list')!)); + const playlist = await this.getSongs.youtubePlaylist(url.searchParams.get('list')!, playlistLimit); + newSongs.push(...playlist); } else { // Single video const song = await this.getSongs.youtubeVideo(url.href); @@ -101,13 +105,13 @@ export default class implements Command { } } } else if (url.protocol === 'spotify:' || url.host === 'open.spotify.com') { - const [convertedSongs, nSongsNotFound, totalSongs] = await this.getSongs.spotifySource(args[0]); + const [convertedSongs, nSongsNotFound, totalSongs] = await this.getSongs.spotifySource(args[0], playlistLimit); - if (totalSongs > 50) { - extraMsg = 'a random sample of 50 songs was taken'; + if (totalSongs > playlistLimit) { + extraMsg = `a random sample of ${playlistLimit} songs was taken`; } - if (totalSongs > 50 && nSongsNotFound !== 0) { + if (totalSongs > playlistLimit && nSongsNotFound !== 0) { extraMsg += ' and '; } @@ -166,4 +170,9 @@ export default class implements Command { await player.play(); } } + + private async getPlaylistLimit(guildId: string) { + const settings = await Settings.findByPk(guildId); + return settings?.playlistLimit ?? 50; + } } diff --git a/src/models/settings.ts b/src/models/settings.ts index 29c2b3e..a2c05c3 100644 --- a/src/models/settings.ts +++ b/src/models/settings.ts @@ -15,4 +15,8 @@ export default class Settings extends Model { @Default(false) @Column finishedSetup!: boolean; + + @Default(50) + @Column + playlistLimit!: number; } diff --git a/src/services/get-songs.ts b/src/services/get-songs.ts index ba4401c..b6f004a 100644 --- a/src/services/get-songs.ts +++ b/src/services/get-songs.ts @@ -97,7 +97,7 @@ export default class { } } - async youtubePlaylist(listId: string): Promise { + async youtubePlaylist(listId: string, limit: number): Promise { // YouTube playlist const playlist = await this.cache.wrap( this.youtube.playlists.get, @@ -126,7 +126,7 @@ export default class { const {items, nextPageToken} = await this.cache.wrap( this.youtube.playlists.items, listId, - {maxResults: '50', pageToken: nextToken}, + {maxResults: `${limit}`, pageToken: nextToken}, { expiresIn: ONE_MINUTE_IN_SECONDS, }, @@ -188,7 +188,7 @@ export default class { return songsToReturn; } - async spotifySource(url: string): Promise<[QueuedSongWithoutChannel[], number, number]> { + async spotifySource(url: string, limit: number): Promise<[QueuedSongWithoutChannel[], number, number]> { const parsed = spotifyURI.parse(url); let tracks: SpotifyApi.TrackObjectSimplified[] = []; @@ -199,7 +199,7 @@ export default class { case 'album': { const uri = parsed as spotifyURI.Album; - const [{body: album}, {body: {items}}] = await Promise.all([this.spotify.getAlbum(uri.id), this.spotify.getAlbumTracks(uri.id, {limit: 50})]); + const [{body: album}, {body: {items}}] = await Promise.all([this.spotify.getAlbum(uri.id), this.spotify.getAlbumTracks(uri.id, {limit})]); tracks.push(...items); @@ -210,7 +210,7 @@ export default class { case 'playlist': { const uri = parsed as spotifyURI.Playlist; - let [{body: playlistResponse}, {body: tracksResponse}] = await Promise.all([this.spotify.getPlaylist(uri.id), this.spotify.getPlaylistTracks(uri.id, {limit: 50})]); + let [{body: playlistResponse}, {body: tracksResponse}] = await Promise.all([this.spotify.getPlaylist(uri.id), this.spotify.getPlaylistTracks(uri.id, {limit})]); playlist = {title: playlistResponse.name, source: playlistResponse.href}; @@ -219,7 +219,7 @@ export default class { while (tracksResponse.next) { // eslint-disable-next-line no-await-in-loop ({body: tracksResponse} = await this.spotify.getPlaylistTracks(uri.id, { - limit: parseInt(new URL(tracksResponse.next).searchParams.get('limit') ?? '50', 10), + limit: parseInt(new URL(tracksResponse.next).searchParams.get('limit') ?? `${limit}`, 10), offset: parseInt(new URL(tracksResponse.next).searchParams.get('offset') ?? '0', 10), })); @@ -252,13 +252,13 @@ export default class { } } - // Get 50 random songs if many + // Get random songs if the playlist is larger than limit const originalNSongs = tracks.length; - if (tracks.length > 50) { + if (tracks.length > limit) { const shuffled = shuffle(tracks); - tracks = shuffled.slice(0, 50); + tracks = shuffled.slice(0, limit); } let songs = await Promise.all(tracks.map(async track => this.spotifyToYouTube(track, playlist))); From 56a899250e22960ec34444241d347e164e037bb2 Mon Sep 17 00:00:00 2001 From: Thongrapee Panyapatiphan Date: Fri, 1 Oct 2021 21:13:37 +0700 Subject: [PATCH 04/10] Remove eslint rule disable statement --- src/commands/play.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/commands/play.ts b/src/commands/play.ts index fce051f..8971cca 100644 --- a/src/commands/play.ts +++ b/src/commands/play.ts @@ -1,4 +1,3 @@ -/* eslint-disable complexity */ import {TextChannel, Message} from 'discord.js'; import {URL} from 'url'; import {Except} from 'type-fest'; From 11eba5746dd8ba3497073c6e7855a43233ca896d Mon Sep 17 00:00:00 2001 From: Thongrapee Panyapatiphan Date: Fri, 1 Oct 2021 22:15:34 +0700 Subject: [PATCH 05/10] Simplify code --- src/services/get-songs.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/services/get-songs.ts b/src/services/get-songs.ts index b6f004a..49628e8 100644 --- a/src/services/get-songs.ts +++ b/src/services/get-songs.ts @@ -126,7 +126,7 @@ export default class { const {items, nextPageToken} = await this.cache.wrap( this.youtube.playlists.items, listId, - {maxResults: `${limit}`, pageToken: nextToken}, + {maxResults: limit, pageToken: nextToken}, { expiresIn: ONE_MINUTE_IN_SECONDS, }, @@ -219,7 +219,7 @@ export default class { while (tracksResponse.next) { // eslint-disable-next-line no-await-in-loop ({body: tracksResponse} = await this.spotify.getPlaylistTracks(uri.id, { - limit: parseInt(new URL(tracksResponse.next).searchParams.get('limit') ?? `${limit}`, 10), + limit, offset: parseInt(new URL(tracksResponse.next).searchParams.get('offset') ?? '0', 10), })); From 4364f459bed721bb2676bd7b5f6b9f2a99b33a2c Mon Sep 17 00:00:00 2001 From: Thongrapee Panyapatiphan Date: Fri, 1 Oct 2021 22:33:39 +0700 Subject: [PATCH 06/10] Add playlist-limit in config command --- src/commands/config.ts | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/commands/config.ts b/src/commands/config.ts index 0e5728a..13186fc 100644 --- a/src/commands/config.ts +++ b/src/commands/config.ts @@ -11,6 +11,7 @@ export default class implements Command { public examples = [ ['config prefix !', 'set the prefix to !'], ['config channel music-commands', 'bind the bot to the music-commands channel'], + ['config playlist-limit 30', 'set the playlist song limit to 30'], ]; public async execute(msg: Message, args: string []): Promise { @@ -20,7 +21,8 @@ export default class implements Command { if (settings) { let response = `prefix: \`${settings.prefix}\`\n`; - response += `channel: ${msg.guild!.channels.cache.get(settings.channel)!.toString()}`; + response += `channel: ${msg.guild!.channels.cache.get(settings.channel)!.toString()}\n`; + response += `playlist-limit: ${settings.playlistLimit}`; await msg.channel.send(response); } @@ -73,6 +75,18 @@ export default class implements Command { break; } + case 'playlist-limit': { + const playlistLimit = Number(args[1]); + if (!playlistLimit || playlistLimit <= 0) { + await msg.channel.send(errorMsg('please enter a valid number')); + return; + } + + await Settings.update({playlistLimit}, {where: {guildId: msg.guild!.id}}); + await msg.channel.send(`👍 playlist-limit updated to ${playlistLimit}`); + break; + } + default: await msg.channel.send(errorMsg('I\'ve never met this setting in my life')); } From 847c578b5d097a4187d58485c1f4c759098c131a Mon Sep 17 00:00:00 2001 From: Thongrapee Panyapatiphan Date: Fri, 1 Oct 2021 23:49:22 +0700 Subject: [PATCH 07/10] Remove custom getter --- src/commands/play.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/commands/play.ts b/src/commands/play.ts index 8971cca..7f02d5e 100644 --- a/src/commands/play.ts +++ b/src/commands/play.ts @@ -40,7 +40,8 @@ export default class implements Command { public async execute(msg: Message, args: string[]): Promise { const [targetVoiceChannel] = getMemberVoiceChannel(msg.member!) ?? getMostPopularVoiceChannel(msg.guild!); - const playlistLimit = await this.getPlaylistLimit(msg.guild!.id); + const settings = await Settings.findByPk(msg.guild!.id); + const {playlistLimit} = settings!; const res = new LoadingMessage(msg.channel as TextChannel); await res.start(); @@ -169,9 +170,4 @@ export default class implements Command { await player.play(); } } - - private async getPlaylistLimit(guildId: string) { - const settings = await Settings.findByPk(guildId); - return settings?.playlistLimit ?? 50; - } } From 33b0ffa244eaa33a75f16790678390aad8f3d3ff Mon Sep 17 00:00:00 2001 From: Thongrapee Panyapatiphan Date: Fri, 1 Oct 2021 23:59:33 +0700 Subject: [PATCH 08/10] Update parsing and validation logic for playlist-limit config --- src/commands/config.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/commands/config.ts b/src/commands/config.ts index 13186fc..cb3fc74 100644 --- a/src/commands/config.ts +++ b/src/commands/config.ts @@ -76,8 +76,8 @@ export default class implements Command { } case 'playlist-limit': { - const playlistLimit = Number(args[1]); - if (!playlistLimit || playlistLimit <= 0) { + const playlistLimit = parseInt(args[1], 10); + if (playlistLimit <= 0) { await msg.channel.send(errorMsg('please enter a valid number')); return; } From 5ce3f92023d56b16c8b15e584084fe90e7ab9b55 Mon Sep 17 00:00:00 2001 From: Thongrapee Panyapatiphan Date: Sat, 18 Dec 2021 14:53:00 +0700 Subject: [PATCH 09/10] Revert incorrect changes --- src/commands/play.ts | 3 +-- src/services/get-songs.ts | 16 ++++++++-------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/commands/play.ts b/src/commands/play.ts index ddaa6bd..c791930 100644 --- a/src/commands/play.ts +++ b/src/commands/play.ts @@ -92,8 +92,7 @@ export default class implements Command { // YouTube source if (url.searchParams.get('list')) { // YouTube playlist - const playlist = await this.getSongs.youtubePlaylist(url.searchParams.get('list')!, playlistLimit); - newSongs.push(...playlist); + newSongs.push(...await this.getSongs.youtubePlaylist(url.searchParams.get('list')!)); } else { // Single video const song = await this.getSongs.youtubeVideo(url.href); diff --git a/src/services/get-songs.ts b/src/services/get-songs.ts index 38a2b61..ebf779a 100644 --- a/src/services/get-songs.ts +++ b/src/services/get-songs.ts @@ -97,7 +97,7 @@ export default class { } } - async youtubePlaylist(listId: string, limit: number): Promise { + async youtubePlaylist(listId: string): Promise { // YouTube playlist const playlist = await this.cache.wrap( this.youtube.playlists.get, @@ -126,7 +126,7 @@ export default class { const {items, nextPageToken} = await this.cache.wrap( this.youtube.playlists.items, listId, - {maxResults: limit, pageToken: nextToken}, + {maxResults: '50', pageToken: nextToken}, { expiresIn: ONE_MINUTE_IN_SECONDS, }, @@ -188,7 +188,7 @@ export default class { return songsToReturn; } - async spotifySource(url: string, limit: number): Promise<[QueuedSongWithoutChannel[], number, number]> { + async spotifySource(url: string, playlistLimit: number): Promise<[QueuedSongWithoutChannel[], number, number]> { const parsed = spotifyURI.parse(url); let tracks: SpotifyApi.TrackObjectSimplified[] = []; @@ -199,7 +199,7 @@ export default class { case 'album': { const uri = parsed as spotifyURI.Album; - const [{body: album}, {body: {items}}] = await Promise.all([this.spotify.getAlbum(uri.id), this.spotify.getAlbumTracks(uri.id, {limit})]); + const [{body: album}, {body: {items}}] = await Promise.all([this.spotify.getAlbum(uri.id), this.spotify.getAlbumTracks(uri.id, {limit: 50})]); tracks.push(...items); @@ -210,7 +210,7 @@ export default class { case 'playlist': { const uri = parsed as spotifyURI.Playlist; - let [{body: playlistResponse}, {body: tracksResponse}] = await Promise.all([this.spotify.getPlaylist(uri.id), this.spotify.getPlaylistTracks(uri.id, {limit})]); + let [{body: playlistResponse}, {body: tracksResponse}] = await Promise.all([this.spotify.getPlaylist(uri.id), this.spotify.getPlaylistTracks(uri.id, {limit: 50})]); playlist = {title: playlistResponse.name, source: playlistResponse.href}; @@ -219,7 +219,7 @@ export default class { while (tracksResponse.next) { // eslint-disable-next-line no-await-in-loop ({body: tracksResponse} = await this.spotify.getPlaylistTracks(uri.id, { - limit, + limit: parseInt(new URL(tracksResponse.next).searchParams.get('limit') ?? '50', 10), offset: parseInt(new URL(tracksResponse.next).searchParams.get('offset') ?? '0', 10), })); @@ -255,10 +255,10 @@ export default class { // Get random songs if the playlist is larger than limit const originalNSongs = tracks.length; - if (tracks.length > limit) { + if (tracks.length > playlistLimit) { const shuffled = shuffle(tracks); - tracks = shuffled.slice(0, limit); + tracks = shuffled.slice(0, playlistLimit); } let songs = await Promise.all(tracks.map(async track => this.spotifyToYouTube(track, playlist))); From f75a76aaa68f647a2540c8074ce7b688bfffeb83 Mon Sep 17 00:00:00 2001 From: Max Isom Date: Sat, 18 Dec 2021 12:16:21 -0600 Subject: [PATCH 10/10] Update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ffc1533..8035eab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Added +- A custom track limit can now be set when queueing playlists from Spotify (default stays at 50). See #370. ## [0.1.1] ### Fixed