From c9cc9a17b13f45786222db948e746b5f8c3742e2 Mon Sep 17 00:00:00 2001 From: Thongrapee Panyapatiphan Date: Fri, 1 Oct 2021 21:11:43 +0700 Subject: [PATCH] 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)));