diff --git a/NadekoBot/Modules/Music/Classes/MusicControls.cs b/NadekoBot/Modules/Music/Classes/MusicControls.cs index 2aba6075..41e8c7c1 100644 --- a/NadekoBot/Modules/Music/Classes/MusicControls.cs +++ b/NadekoBot/Modules/Music/Classes/MusicControls.cs @@ -12,7 +12,8 @@ namespace NadekoBot.Modules.Music.Classes { Radio, Normal, - Local + Local, + Soundcloud } public enum StreamState diff --git a/NadekoBot/Modules/Music/Classes/Song.cs b/NadekoBot/Modules/Music/Classes/Song.cs index b23c75a5..e718302e 100644 --- a/NadekoBot/Modules/Music/Classes/Song.cs +++ b/NadekoBot/Modules/Music/Classes/Song.cs @@ -245,16 +245,30 @@ namespace NadekoBot.Modules.Music.Classes } if (SoundCloud.Default.IsSoundCloudLink(query)) { - var svideo = await SoundCloud.Default.GetVideoAsync(query).ConfigureAwait(false); + var svideo = await SoundCloud.Default.ResolveVideoAsync(query).ConfigureAwait(false); return new Song(new SongInfo { Title = svideo.FullName, Provider = "SoundCloud", Uri = svideo.StreamLink, ProviderType = musicType, - Query = query, + Query = svideo.TrackLink, }); } + + if (musicType == MusicType.Soundcloud) + { + var svideo = await SoundCloud.Default.GetVideoByQueryAsync(query).ConfigureAwait(false); + return new Song(new SongInfo + { + Title = svideo.FullName, + Provider = "SoundCloud", + Uri = svideo.StreamLink, + ProviderType = MusicType.Normal, + Query = svideo.TrackLink, + }); + } + var link = await SearchHelper.FindYoutubeUrlByKeywords(query).ConfigureAwait(false); if (string.IsNullOrWhiteSpace(link)) throw new OperationCanceledException("Not a valid youtube query."); diff --git a/NadekoBot/Modules/Music/Classes/SoundCloud.cs b/NadekoBot/Modules/Music/Classes/SoundCloud.cs index 159d0d9e..e743fa5c 100644 --- a/NadekoBot/Modules/Music/Classes/SoundCloud.cs +++ b/NadekoBot/Modules/Music/Classes/SoundCloud.cs @@ -1,6 +1,7 @@ ๏ปฟusing NadekoBot.Classes; using Newtonsoft.Json; using System; +using System.Linq; using System.Threading.Tasks; namespace NadekoBot.Modules.Music.Classes @@ -13,7 +14,7 @@ namespace NadekoBot.Modules.Music.Classes static SoundCloud() { } public SoundCloud() { } - public async Task GetVideoAsync(string url) + public async Task ResolveVideoAsync(string url) { if (string.IsNullOrWhiteSpace(url)) throw new ArgumentNullException(nameof(url)); @@ -31,6 +32,22 @@ namespace NadekoBot.Modules.Music.Classes public bool IsSoundCloudLink(string url) => System.Text.RegularExpressions.Regex.IsMatch(url, "(.*)(soundcloud.com|snd.sc)(.*)"); + + internal async Task GetVideoByQueryAsync(string query) + { + if (string.IsNullOrWhiteSpace(query)) + throw new ArgumentNullException(nameof(query)); + if (string.IsNullOrWhiteSpace(NadekoBot.Creds.SoundCloudClientID)) + throw new ArgumentNullException(nameof(NadekoBot.Creds.SoundCloudClientID)); + + var response = await SearchHelper.GetResponseStringAsync($"http://api.soundcloud.com/tracks?q={Uri.EscapeDataString(query)}&client_id={NadekoBot.Creds.SoundCloudClientID}").ConfigureAwait(false); + + var responseObj = JsonConvert.DeserializeObject(response).Where(s => s.Streamable).FirstOrDefault(); + if (responseObj?.Kind != "track") + throw new InvalidOperationException("Query yielded no results."); + + return responseObj; + } } public class SoundCloudVideo diff --git a/NadekoBot/Modules/Music/MusicModule.cs b/NadekoBot/Modules/Music/MusicModule.cs index 337529c0..5199cbb1 100644 --- a/NadekoBot/Modules/Music/MusicModule.cs +++ b/NadekoBot/Modules/Music/MusicModule.cs @@ -108,20 +108,20 @@ namespace NadekoBot.Modules.Music } }); - //cgb.CreateCommand("soundcloudqueue") - // .Alias("sq") - // .Description("Queue a soundcloud song using keywords. Bot will join your voice channel." + - // "**You must be in a voice channel**.\n**Usage**: `!m sq Dream Of Venice`") - // .Parameter("query", ParameterType.Unparsed) - // .Do(async e => - // { - // await QueueSong(e.Channel, e.User.VoiceChannel, e.GetArg("query")).ConfigureAwait(false); - // if (e.Server.CurrentUser.GetPermissions(e.Channel).ManageMessages) - // { - // await Task.Delay(10000).ConfigureAwait(false); - // await e.Message.Delete().ConfigureAwait(false); - // } - // }); + cgb.CreateCommand("soundcloudqueue") + .Alias("sq") + .Description("Queue a soundcloud song using keywords. Bot will join your voice channel." + + "**You must be in a voice channel**.\n**Usage**: `!m sq Dream Of Venice`") + .Parameter("query", ParameterType.Unparsed) + .Do(async e => + { + await QueueSong(e.User, e.Channel, e.User.VoiceChannel, e.GetArg("query"), musicType: MusicType.Soundcloud).ConfigureAwait(false); + if (e.Server.CurrentUser.GetPermissions(e.Channel).ManageMessages) + { + await Task.Delay(10000).ConfigureAwait(false); + await e.Message.Delete().ConfigureAwait(false); + } + }); cgb.CreateCommand("listqueue") .Alias("lq") @@ -297,7 +297,7 @@ namespace NadekoBot.Modules.Music var ids = await SearchHelper.GetVideoIDs(plId, 500).ConfigureAwait(false); if (ids == null || ids.Count == 0) { - await e.Channel.SendMessage($"๐ŸŽต `Failed to find any songs.`"); + await e.Channel.SendMessage($"๐ŸŽต `Failed to find any songs.`").ConfigureAwait(false); return; } //todo TEMPORARY SOLUTION, USE RESOLVE QUEUE IN THE FUTURE @@ -329,8 +329,8 @@ namespace NadekoBot.Modules.Music if (string.IsNullOrWhiteSpace(pl)) return; - var scvids = JObject.Parse(await SearchHelper.GetResponseStringAsync($"http://api.soundcloud.com/resolve?url={pl}&client_id={NadekoBot.Creds.SoundCloudClientID}"))["tracks"].ToObject(); - await QueueSong(e.User, e.Channel, e.User.VoiceChannel, scvids[0].TrackLink); + var scvids = JObject.Parse(await SearchHelper.GetResponseStringAsync($"http://api.soundcloud.com/resolve?url={pl}&client_id={NadekoBot.Creds.SoundCloudClientID}").ConfigureAwait(false))["tracks"].ToObject(); + await QueueSong(e.User, e.Channel, e.User.VoiceChannel, scvids[0].TrackLink).ConfigureAwait(false); MusicPlayer mp; if (!MusicPlayers.TryGetValue(e.Server, out mp)) @@ -483,7 +483,7 @@ namespace NadekoBot.Modules.Music !int.TryParse(fromtoArr[1], out n2) || n1 < 1 || n2 < 1 || n1 == n2 || n1 > playlist.Count || n2 > playlist.Count) { - await e.Channel.SendMessage("`Invalid input.`"); + await e.Channel.SendMessage("`Invalid input.`").ConfigureAwait(false); return; } @@ -492,7 +492,7 @@ namespace NadekoBot.Modules.Music var nn1 = n2 < n1 ? n1 : n1 - 1; playlist.RemoveAt(nn1); - await e.Channel.SendMessage($"๐ŸŽต`Moved` {s.PrettyName} `from #{n1} to #{n2}`"); + await e.Channel.SendMessage($"๐ŸŽต`Moved` {s.PrettyName} `from #{n1} to #{n2}`").ConfigureAwait(false); }); @@ -691,9 +691,9 @@ namespace NadekoBot.Modules.Music return; var result = DbHandler.Instance.GetPlaylistData(num); if (result.Count == 0) - e.Channel.SendMessage($"`No saved playlists found on page {num}`"); + e.Channel.SendMessage($"`No saved playlists found on page {num}`").ConfigureAwait(false); else - e.Channel.SendMessage($"```js\n--- List of saved playlists ---\n\n" + string.Join("\n", result.Select(r => $"'{r.Name}-{r.Id}' by {r.Creator} ({r.SongCnt} songs)")) + $"\n\n --- Page {num} ---```"); + e.Channel.SendMessage($"```js\n--- List of saved playlists ---\n\n" + string.Join("\n", result.Select(r => $"'{r.Name}-{r.Id}' by {r.Creator} ({r.SongCnt} songs)")) + $"\n\n --- Page {num} ---```").ConfigureAwait(false); }); cgb.CreateCommand("deleteplaylist") @@ -710,7 +710,7 @@ namespace NadekoBot.Modules.Music DbHandler.Instance.Delete(plnum); else DbHandler.Instance.DeleteWhere(mp => mp.Id == plnum && (long)e.User.Id == mp.CreatorId); - await e.Channel.SendMessage("`Ok.` :ok:"); + await e.Channel.SendMessage("`Ok.` :ok:").ConfigureAwait(false); }); cgb.CreateCommand("goto") @@ -761,7 +761,7 @@ namespace NadekoBot.Modules.Music var curSong = musicPlayer.CurrentSong; if (curSong == null) return; - await e.Channel.SendMessage($"๐ŸŽถ`Current song:` <{curSong.SongInfo.Query}>"); + await e.Channel.SendMessage($"๐ŸŽถ`Current song:` <{curSong.SongInfo.Query}>").ConfigureAwait(false); }); cgb.CreateCommand("autoplay") @@ -775,9 +775,9 @@ namespace NadekoBot.Modules.Music return; if (!musicPlayer.ToggleAutoplay()) - await e.Channel.SendMessage("๐ŸŽถ`Autoplay disabled.`"); + await e.Channel.SendMessage("๐ŸŽถ`Autoplay disabled.`").ConfigureAwait(false); else - await e.Channel.SendMessage("๐ŸŽถ`Autoplay enabled.`"); + await e.Channel.SendMessage("๐ŸŽถ`Autoplay enabled.`").ConfigureAwait(false); }); }); } diff --git a/NadekoBot/Modules/Utility/UtilityModule.cs b/NadekoBot/Modules/Utility/UtilityModule.cs index 6d510a25..c85348aa 100644 --- a/NadekoBot/Modules/Utility/UtilityModule.cs +++ b/NadekoBot/Modules/Utility/UtilityModule.cs @@ -99,7 +99,7 @@ namespace NadekoBot.Modules.Utility .Description("Shows some basic stats for Nadeko.") .Do(async e => { - await e.Channel.SendMessage(await NadekoStats.Instance.GetStats()); + await e.Channel.SendMessage(await NadekoStats.Instance.GetStats()).ConfigureAwait(false); }); cgb.CreateCommand(Prefix + "dysyd")