From 80e749a1a1b0b96e4283735aeca0c5ee0f2c2eba Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 1 Oct 2016 05:49:05 +0200 Subject: [PATCH] Playlist loading, saving and listing done --- .../NadekoSqliteContextModelSnapshot.cs | 45 +++++++ .../Modules/Administration/Administration.cs | 9 +- src/NadekoBot/Modules/Help/Help.cs | 3 +- .../Modules/Music/Classes/MusicControls.cs | 2 +- src/NadekoBot/Modules/Music/Music.cs | 116 +++++++++++++----- src/NadekoBot/NadekoBot.cs | 6 +- src/NadekoBot/Services/CommandHandler.cs | 23 ++-- .../Services/Database/NadekoContext.cs | 1 + src/NadekoBot/Services/Database/UnitOfWork.cs | 4 + src/NadekoBot/Services/Impl/BotCredentials.cs | 3 + 10 files changed, 162 insertions(+), 50 deletions(-) diff --git a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs index 210b97e9..949720d0 100644 --- a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs +++ b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs @@ -356,6 +356,20 @@ namespace NadekoBot.Migrations b.ToTable("ModulePrefixes"); }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.MusicPlaylist", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Author"); + + b.Property("Name"); + + b.HasKey("Id"); + + b.ToTable("MusicPlaylists"); + }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.Permission", b => { b.Property("Id") @@ -397,6 +411,30 @@ namespace NadekoBot.Migrations b.ToTable("PlayingStatus"); }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.PlaylistSong", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("MusicPlaylistId"); + + b.Property("Provider"); + + b.Property("ProviderType"); + + b.Property("Query"); + + b.Property("Title"); + + b.Property("Uri"); + + b.HasKey("Id"); + + b.HasIndex("MusicPlaylistId"); + + b.ToTable("PlaylistSong"); + }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.Quote", b => { b.Property("Id") @@ -588,6 +626,13 @@ namespace NadekoBot.Migrations .HasForeignKey("BotConfigId"); }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.PlaylistSong", b => + { + b.HasOne("NadekoBot.Services.Database.Models.MusicPlaylist") + .WithMany("Songs") + .HasForeignKey("MusicPlaylistId"); + }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.RaceAnimal", b => { b.HasOne("NadekoBot.Services.Database.Models.BotConfig") diff --git a/src/NadekoBot/Modules/Administration/Administration.cs b/src/NadekoBot/Modules/Administration/Administration.cs index a3ba38df..e82aa16f 100644 --- a/src/NadekoBot/Modules/Administration/Administration.cs +++ b/src/NadekoBot/Modules/Administration/Administration.cs @@ -614,10 +614,11 @@ namespace NadekoBot.Modules.Administration { var channel = (ITextChannel)umsg.Channel; - foreach (var ch in _client.GetGuilds().Select(async g => await g.GetDefaultChannelAsync().ConfigureAwait(false))) - { - await channel.SendMessageAsync(message).ConfigureAwait(false); - } + var channels = await Task.WhenAll(_client.GetGuilds().Select(g => + g.GetDefaultChannelAsync() + )).ConfigureAwait(false); + + await Task.WhenAll(channels.Select(c => c.SendMessageAsync($"`Message from {umsg.Author} (Bot Owner):` " + message))); await channel.SendMessageAsync(":ok:").ConfigureAwait(false); } diff --git a/src/NadekoBot/Modules/Help/Help.cs b/src/NadekoBot/Modules/Help/Help.cs index 5dc88748..f4c2dbcc 100644 --- a/src/NadekoBot/Modules/Help/Help.cs +++ b/src/NadekoBot/Modules/Help/Help.cs @@ -84,7 +84,8 @@ Nadeko Support Server: https://discord.gg/0ehQwTK2RBjAxzEY"; comToFind = comToFind?.ToLowerInvariant(); if (string.IsNullOrWhiteSpace(comToFind)) { - await (await (umsg.Author as IGuildUser).CreateDMChannelAsync()).SendMessageAsync(HelpString).ConfigureAwait(false); + IMessageChannel ch = channel is ITextChannel ? await ((IGuildUser)umsg.Author).CreateDMChannelAsync() : channel; + await ch.SendMessageAsync(HelpString).ConfigureAwait(false); return; } var com = _commands.Commands.FirstOrDefault(c => c.Text.ToLowerInvariant() == comToFind || c.Aliases.Select(a=>a.ToLowerInvariant()).Contains(comToFind)); diff --git a/src/NadekoBot/Modules/Music/Classes/MusicControls.cs b/src/NadekoBot/Modules/Music/Classes/MusicControls.cs index 233bca09..fa4e2302 100644 --- a/src/NadekoBot/Modules/Music/Classes/MusicControls.cs +++ b/src/NadekoBot/Modules/Music/Classes/MusicControls.cs @@ -252,7 +252,7 @@ namespace NadekoBot.Modules.Music.Classes playlist.Clear(); if (!SongCancelSource.IsCancellationRequested) SongCancelSource.Cancel(); - await audioClient.DisconnectAsync(); + await audioClient.DisconnectAsync(); }); } diff --git a/src/NadekoBot/Modules/Music/Music.cs b/src/NadekoBot/Modules/Music/Music.cs index abc9702d..21e8e26f 100644 --- a/src/NadekoBot/Modules/Music/Music.cs +++ b/src/NadekoBot/Modules/Music/Music.cs @@ -14,6 +14,7 @@ using System.Net.Http; using Newtonsoft.Json.Linq; using System.Collections.Generic; using NadekoBot.Services.Database; +using NadekoBot.Services.Database.Models; namespace NadekoBot.Modules.Music { @@ -520,48 +521,95 @@ namespace NadekoBot.Modules.Music await channel.SendMessageAsync($"🎵🔁`Repeat playlist {(currentValue ? "enabled" : "disabled")}`").ConfigureAwait(false); } - //[LocalizedCommand, LocalizedRemarks, LocalizedSummary, LocalizedAlias] - //[RequireContext(ContextType.Guild)] - //public async Task Save(IUserMessage umsg, [Remainder] string name) - //{ - // var channel = (ITextChannel)umsg.Channel; - // MusicPlayer musicPlayer; - // if (!MusicPlayers.TryGetValue(channel.Guild.Id, out musicPlayer)) - // return; + [LocalizedCommand, LocalizedRemarks, LocalizedSummary, LocalizedAlias] + [RequireContext(ContextType.Guild)] + public async Task Save(IUserMessage umsg, [Remainder] string name) + { + var channel = (ITextChannel)umsg.Channel; + MusicPlayer musicPlayer; + if (!MusicPlayers.TryGetValue(channel.Guild.Id, out musicPlayer)) + return; - // var curSong = musicPlayer.CurrentSong; - // var items = musicPlayer.Playlist.Append(curSong); + var curSong = musicPlayer.CurrentSong; + var songs = musicPlayer.Playlist.Append(curSong) + .Select(s=> new PlaylistSong() { + Provider = s.SongInfo.Provider, + ProviderType = s.SongInfo.ProviderType, + Title = s.SongInfo.Title, + Uri = s.SongInfo.Uri, + Query = s.SongInfo.Query, + }).ToList(); - // MusicPlaylist playlist; - // using (var uow = DbHandler.UnitOfWork()) - // { - // playlist = new MusicPlaylist - // { - // Name = name, - // Songs = items.ToList() - // }; - // uow.MusicPlaylists.Add(playlist); - // } + MusicPlaylist playlist; + using (var uow = DbHandler.UnitOfWork()) + { + playlist = new MusicPlaylist + { + Name = name, + Author = umsg.Author.Username, + Songs = songs, + }; + uow.MusicPlaylists.Add(playlist); + await uow.CompleteAsync().ConfigureAwait(false); + } - // await channel.SendMessageAsync($"Playlist saved as {name}, id: {playlist.Id}."); - //} + await channel.SendMessageAsync(($"🎵 `Saved playlist as {name}.` `Id: {playlist.Id}`")).ConfigureAwait(false); + } - //[LocalizedCommand, LocalizedRemarks, LocalizedSummary, LocalizedAlias] - //[RequireContext(ContextType.Guild)] - //public async Task Load(IUserMessage umsg, [Remainder] string name) - //{ - // var channel = (ITextChannel)umsg.Channel; + [LocalizedCommand, LocalizedRemarks, LocalizedSummary, LocalizedAlias] + [RequireContext(ContextType.Guild)] + public async Task Load(IUserMessage umsg, [Remainder] int id) + { + var channel = (ITextChannel)umsg.Channel; - //} + MusicPlaylist mpl; + using (var uow = DbHandler.UnitOfWork()) + { + mpl = uow.MusicPlaylists.GetWithSongs(id); + } - //[LocalizedCommand, LocalizedRemarks, LocalizedSummary, LocalizedAlias] - //[RequireContext(ContextType.Guild)] - //public async Task Playlists(IUserMessage umsg, [Remainder] string num) - //{ - // var channel = (ITextChannel)umsg.Channel; + if (mpl == null) + { + await channel.SendMessageAsync("Can't find playlist with that ID").ConfigureAwait(false); + return; + } - //} + var msg = await channel.SendMessageAsync($"`Attempting to load {mpl.Songs.Count} songs...`").ConfigureAwait(false); + foreach (var item in mpl.Songs) + { + try + { + var usr = (IGuildUser)umsg.Author; + await QueueSong(usr, channel, usr.VoiceChannel, item.Query, true, item.ProviderType).ConfigureAwait(false); + } + catch { break; } + } + await msg.ModifyAsync(m => m.Content = $"`Done loading playlist {mpl.Name}.`").ConfigureAwait(false); + } + + [LocalizedCommand, LocalizedRemarks, LocalizedSummary, LocalizedAlias] + [RequireContext(ContextType.Guild)] + public async Task Playlists(IUserMessage umsg, [Remainder] int num = 1) + { + var channel = (ITextChannel)umsg.Channel; + + if (num <= 0) + return; + + List playlists; + + using (var uow = DbHandler.UnitOfWork()) + { + playlists = uow.MusicPlaylists.GetPlaylistsOnPage(num); + } + + await channel.SendMessageAsync($@"`Page {num} of saved playlists` + +" + string.Join("\n", playlists.Select(r => $"`#{r.Id}` - `{r.Name}` by {r.Author} - **{r.Songs.Count}** songs"))).ConfigureAwait(false); + } + + //todo only author or owner //[LocalizedCommand, LocalizedRemarks, LocalizedSummary, LocalizedAlias] //[RequireContext(ContextType.Guild)] //public async Task DeletePlaylist(IUserMessage umsg, [Remainder] string pl) diff --git a/src/NadekoBot/NadekoBot.cs b/src/NadekoBot/NadekoBot.cs index 9d4b0985..bf26ad28 100644 --- a/src/NadekoBot/NadekoBot.cs +++ b/src/NadekoBot/NadekoBot.cs @@ -42,16 +42,20 @@ namespace NadekoBot _log.Info("Starting NadekoBot v" + typeof(NadekoBot).GetTypeInfo().Assembly.GetCustomAttribute().InformationalVersion); + + Credentials = new BotCredentials(); + //create client Client = new ShardedDiscordClient (new DiscordSocketConfig { AudioMode = Discord.Audio.AudioMode.Outgoing, MessageCacheSize = 10, LogLevel = LogSeverity.Warning, + TotalShards = Credentials.TotalShards, + ConnectionTimeout = 60000 }); //initialize Services - Credentials = new BotCredentials(); CommandService = new CommandService(); Localizer = new Localization(); Google = new GoogleApiService(); diff --git a/src/NadekoBot/Services/CommandHandler.cs b/src/NadekoBot/Services/CommandHandler.cs index 75f43088..1a4e65f9 100644 --- a/src/NadekoBot/Services/CommandHandler.cs +++ b/src/NadekoBot/Services/CommandHandler.cs @@ -43,22 +43,27 @@ namespace NadekoBot.Services var throwaway = Task.Run(async () => { - var sw = new Stopwatch(); + var sw = new Stopwatch(); sw.Start(); try { - bool verbose; - Permission rootPerm; - string permRole; - using (var uow = DbHandler.UnitOfWork()) + + bool verbose = false; + Permission rootPerm = null; + string permRole = ""; + if (guild != null) { - var config = uow.GuildConfigs.PermissionsFor(guild.Id); - verbose = config.VerbosePermissions; - rootPerm = config.RootPermission; - permRole = config.PermissionRole.Trim().ToLowerInvariant(); + using (var uow = DbHandler.UnitOfWork()) + { + var config = uow.GuildConfigs.PermissionsFor(guild.Id); + verbose = config.VerbosePermissions; + rootPerm = config.RootPermission; + permRole = config.PermissionRole.Trim().ToLowerInvariant(); + } } + var t = await ExecuteCommand(usrMsg, usrMsg.Content, guild, usrMsg.Author, rootPerm, permRole, MultiMatchHandling.Best); var command = t.Item1; var result = t.Item2; diff --git a/src/NadekoBot/Services/Database/NadekoContext.cs b/src/NadekoBot/Services/Database/NadekoContext.cs index 6d71f8cc..ea4242f2 100644 --- a/src/NadekoBot/Services/Database/NadekoContext.cs +++ b/src/NadekoBot/Services/Database/NadekoContext.cs @@ -22,6 +22,7 @@ namespace NadekoBot.Services.Database public DbSet Currency { get; set; } public DbSet ConversionUnits { get; set; } public DbSet TypingArticles { get; set; } + public DbSet MusicPlaylists { get; set; } //logging public DbSet LogSettings { get; set; } diff --git a/src/NadekoBot/Services/Database/UnitOfWork.cs b/src/NadekoBot/Services/Database/UnitOfWork.cs index b2b84e3e..33f5d1c1 100644 --- a/src/NadekoBot/Services/Database/UnitOfWork.cs +++ b/src/NadekoBot/Services/Database/UnitOfWork.cs @@ -38,12 +38,16 @@ namespace NadekoBot.Services.Database private ICurrencyRepository _currency; public ICurrencyRepository Currency => _currency ?? (_currency = new CurrencyRepository(_context)); + private IUnitConverterRepository _conUnits; public IUnitConverterRepository ConverterUnits => _conUnits ?? (_conUnits = new UnitConverterRepository(_context)); private ITypingArticlesRepository _typingArticles; public ITypingArticlesRepository TypingArticles => _typingArticles ?? (_typingArticles = new TypingArticlesRepository(_context)); + private IMusicPlaylistRepository _musicPlaylists; + public IMusicPlaylistRepository MusicPlaylists => _musicPlaylists ?? (_musicPlaylists = new MusicPlaylistRepository(_context)); + public UnitOfWork(NadekoContext context) { _context = context; diff --git a/src/NadekoBot/Services/Impl/BotCredentials.cs b/src/NadekoBot/Services/Impl/BotCredentials.cs index 23e4fcb9..0d420528 100644 --- a/src/NadekoBot/Services/Impl/BotCredentials.cs +++ b/src/NadekoBot/Services/Impl/BotCredentials.cs @@ -27,6 +27,7 @@ namespace NadekoBot.Services.Impl public string SoundCloudClientId { get; } public DB Db { get; } + public int TotalShards { get; } public BotCredentials() { @@ -40,6 +41,7 @@ namespace NadekoBot.Services.Impl GoogleApiKey = cm.GoogleApiKey; MashapeKey = cm.MashapeKey; OsuApiKey = cm.OsuApiKey; + TotalShards = cm.TotalShards < 1 ? 1 : cm.TotalShards; SoundCloudClientId = cm.SoundCloudClientId; if (cm.Db == null) Db = new DB("sqlite", ""); @@ -60,6 +62,7 @@ namespace NadekoBot.Services.Impl public string OsuApiKey { get; set; } public string SoundCloudClientId { get; set; } public DB Db { get; set; } + public int TotalShards { get; set; } = 1; } private class DbModel