diff --git a/ComprehensiveGuide.md b/ComprehensiveGuide.md index 02be077f..1f80dbb9 100644 --- a/ComprehensiveGuide.md +++ b/ComprehensiveGuide.md @@ -10,7 +10,7 @@ ________________________________________________________________________________ - Go to (https://discordapp.com/developers/applications/me). Log in if you have to with your Discord account. Press "New Application" and fill out an App Name and, optionally, an app description and icon. Afterwards, create the application. Once the application is created, click on "Create a Bot User" and confirm it. You will then see the bot's username, ID and token. Reveal and copy the token and the bot ID. - Open up credentials.json. Paste the token into the Token field, between the quotes. Paste the ID into the BotID field. Leave email and password fields empty. Save and close credentials.json. - Go into data folder and make sure you have config.json file. If there is no config.json, rename the config_example.json to config.json. -- Copy your CLIENT ID (that's in the same Developer page where you brought your token) and replace `12345678` in the this link: +- Copy your CLIENT ID (that's in the same Developer page where you brought your token) and replace `12345678` in this link: https://discordapp.com/oauth2/authorize?client_id=12345678&scope=bot&permissions=66186303 with it. Go to that link and you will be able to add your bot to your server. - Start NadekoBot.exe. In a text channel, **not a direct message**, type in [.uid @______] without the brackets, filling in the underlined portion with your name and send the message. Your bot will reply with a number; this is your ID. Copy this ID and close NadekoBot.exe. - Reopen credentials.json. Paste your ID into the square brackets ("OwnerIds": [1231312313]). You can add multiple owners by separating IDs with a comma. Close and save credentials.json. diff --git a/NadekoBot.sln b/NadekoBot.sln index 5e8a3b96..e7681a7d 100644 --- a/NadekoBot.sln +++ b/NadekoBot.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.25008.0 +VisualStudioVersion = 14.0.25123.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NadekoBot", "NadekoBot\NadekoBot.csproj", "{27A886F5-CDDA-4F4A-81EE-6DAFCCE9DE46}" EndProject diff --git a/NadekoBot/Classes/DBHandler.cs b/NadekoBot/Classes/DBHandler.cs index b6b85c9c..caf1cd22 100644 --- a/NadekoBot/Classes/DBHandler.cs +++ b/NadekoBot/Classes/DBHandler.cs @@ -158,9 +158,35 @@ namespace NadekoBot.Classes return conn.Table().Where(p).ToList().OrderBy(x => r.Next()).FirstOrDefault(); } } + /// + /// + /// + /// Page number (0+) + /// + internal List GetPlaylistData(int num) + { + using (var conn = new SQLiteConnection(FilePath)) + { + return conn.Query( +@"SELECT mp.Name as 'Name',mp.Id as 'Id', mp.CreatorName as 'Creator', Count(*) as 'SongCnt' FROM MusicPlaylist as mp +INNER JOIN PlaylistSongInfo as psi +ON mp.Id = psi.PlaylistId +Group BY mp.Name +Order By mp.DateAdded desc +Limit 20 OFFSET ?", num * 20); + } + } } } +public class PlaylistData +{ + public string Name { get; set; } + public int Id { get; set; } + public string Creator { get; set; } + public int SongCnt { get; set; } +} + public static class Queries { public static string TransactionTriggerQuery = @" diff --git a/NadekoBot/Classes/Extensions.cs b/NadekoBot/Classes/Extensions.cs index fea6b61a..c3062c5f 100644 --- a/NadekoBot/Classes/Extensions.cs +++ b/NadekoBot/Classes/Extensions.cs @@ -138,14 +138,21 @@ namespace NadekoBot.Extensions /// public static void Shuffle(this IList list) { + + // Thanks to @Joe4Evr for finding a bug in the old version of the shuffle var provider = new RNGCryptoServiceProvider(); var n = list.Count; while (n > 1) { - var box = new byte[1]; - do provider.GetBytes(box); - while (!(box[0] < n * (byte.MaxValue / n))); - var k = (box[0] % n); + var box = new byte[(n / Byte.MaxValue) + 1]; + int boxSum; + do + { + provider.GetBytes(box); + boxSum = box.Sum(b => b); + } + while (!(boxSum < n * ((Byte.MaxValue * box.Length) / n))); + var k = (boxSum % n); n--; var value = list[k]; list[k] = list[n]; diff --git a/NadekoBot/Classes/NadekoStats.cs b/NadekoBot/Classes/NadekoStats.cs index 69dcdf70..483e2214 100644 --- a/NadekoBot/Classes/NadekoStats.cs +++ b/NadekoBot/Classes/NadekoStats.cs @@ -219,9 +219,10 @@ namespace NadekoBot DateAdded = DateTime.Now }); } - catch + catch (Exception ex) { - Console.WriteLine("Error in ran command DB write."); + Console.WriteLine("Probably unimportant error in ran command DB write."); + Console.WriteLine(ex); } }).ConfigureAwait(false); } diff --git a/NadekoBot/Classes/SearchHelper.cs b/NadekoBot/Classes/SearchHelper.cs index b8b7a8b5..ad78466f 100644 --- a/NadekoBot/Classes/SearchHelper.cs +++ b/NadekoBot/Classes/SearchHelper.cs @@ -263,12 +263,19 @@ namespace NadekoBot.Classes { try { - XDocument doc = await Task.Run(() => XDocument.Load(" http://e621.net/post/index.xml?tags=" + Uri.EscapeUriString(tags) + "%20order:random&limit=1")); - int id = Convert.ToInt32(doc.Root.Element("post").Element("id").Value); - return (doc.Root.Element("post").Element("file_url").Value); + var headers = new Dictionary() { + {"User-Agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.202 Safari/535.1"}, + {"Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" }, + }; + var data = await GetResponseStreamAsync( + "http://e621.net/post/index.xml?tags=" + Uri.EscapeUriString(tags) + "%20order:random&limit=1", + headers); + var doc = XDocument.Load(data); + return doc.Descendants("file_url").FirstOrDefault().Value; } - catch (Exception) + catch (Exception ex) { + Console.WriteLine("Error in e621 search: \n" + ex); return "Error, do you have too many tags?"; } } diff --git a/NadekoBot/Modules/Administration/Commands/ServerGreetCommand.cs b/NadekoBot/Modules/Administration/Commands/ServerGreetCommand.cs index de915b73..398ce975 100644 --- a/NadekoBot/Modules/Administration/Commands/ServerGreetCommand.cs +++ b/NadekoBot/Modules/Administration/Commands/ServerGreetCommand.cs @@ -69,9 +69,9 @@ namespace NadekoBot.Modules.Administration.Commands if (channel == null) return; Greeted++; var toDelete = await channel.SendMessage(msg).ConfigureAwait(false); - if (e.Server.CurrentUser.GetPermissions(channel).ManageMessages) + if (e.Server.CurrentUser.GetPermissions(channel).ManageMessages && controls.DeleteGreetMessages) { - await Task.Delay(300000).ConfigureAwait(false); // 5 minutes + await Task.Delay(30000).ConfigureAwait(false); // 5 minutes await toDelete.Delete().ConfigureAwait(false); } } @@ -102,9 +102,9 @@ namespace NadekoBot.Modules.Administration.Commands if (channel == null) return; Greeted++; var toDelete = await channel.SendMessage(msg).ConfigureAwait(false); - if (e.Server.CurrentUser.GetPermissions(channel).ManageMessages) + if (e.Server.CurrentUser.GetPermissions(channel).ManageMessages && controls.DeleteGreetMessages) { - await Task.Delay(300000).ConfigureAwait(false); // 5 minutes + await Task.Delay(30000).ConfigureAwait(false); // 5 minutes await toDelete.Delete().ConfigureAwait(false); } } @@ -160,6 +160,15 @@ namespace NadekoBot.Modules.Administration.Commands set { _model.ServerId = (long)value; } } + public bool DeleteGreetMessages { + get { + return _model.DeleteGreetMessages; + } + set { + _model.DeleteGreetMessages = value; Save(); + } + } + public AnnounceControls(DataModels.Announcement model) { this._model = model; @@ -196,6 +205,8 @@ namespace NadekoBot.Modules.Administration.Commands return Greet = true; } } + + internal bool ToggleDelete() => DeleteGreetMessages = !DeleteGreetMessages; internal bool ToggleGreetPM() => GreetPM = !GreetPM; internal bool ToggleByePM() => ByePM = !ByePM; @@ -207,18 +218,27 @@ namespace NadekoBot.Modules.Administration.Commands internal override void Init(CommandGroupBuilder cgb) { + cgb.CreateCommand(Module.Prefix + "grdel") + .Description("Enables or Disables automatic deletion of greet and bye messages.") + .Do(async e => + { + if (!e.User.ServerPermissions.ManageServer) return; + var ann = AnnouncementsDictionary.GetOrAdd(e.Server.Id, new AnnounceControls(e.Server.Id)); + + if (ann.ToggleDelete()) + await e.Channel.SendMessage("`Automatic deletion of greet and bye messages has been enabled.`").ConfigureAwait(false); + else + await e.Channel.SendMessage("`Automatic deletion of greet and bye messages has been disabled.`").ConfigureAwait(false); + }); cgb.CreateCommand(Module.Prefix + "greet") .Description("Enables or Disables anouncements on the current channel when someone joins the server.") .Do(async e => { if (!e.User.ServerPermissions.ManageServer) return; - if (!AnnouncementsDictionary.ContainsKey(e.Server.Id)) - AnnouncementsDictionary.TryAdd(e.Server.Id, new AnnounceControls(e.Server.Id)); + var ann = AnnouncementsDictionary.GetOrAdd(e.Server.Id, new AnnounceControls(e.Server.Id)); - var controls = AnnouncementsDictionary[e.Server.Id]; - - if (controls.ToggleGreet(e.Channel.Id)) + if (ann.ToggleGreet(e.Channel.Id)) await e.Channel.SendMessage("Greet announcements enabled on this channel.").ConfigureAwait(false); else await e.Channel.SendMessage("Greet announcements disabled.").ConfigureAwait(false); @@ -231,12 +251,11 @@ namespace NadekoBot.Modules.Administration.Commands { if (!e.User.ServerPermissions.ManageServer) return; if (e.GetArg("msg") == null) return; - if (!AnnouncementsDictionary.ContainsKey(e.Server.Id)) - AnnouncementsDictionary.TryAdd(e.Server.Id, new AnnounceControls(e.Server.Id)); + var ann = AnnouncementsDictionary.GetOrAdd(e.Server.Id, new AnnounceControls(e.Server.Id)); - AnnouncementsDictionary[e.Server.Id].GreetText = e.GetArg("msg"); + ann.GreetText = e.GetArg("msg"); await e.Channel.SendMessage("New greet message set.").ConfigureAwait(false); - if (!AnnouncementsDictionary[e.Server.Id].Greet) + if (!ann.Greet) await e.Channel.SendMessage("Enable greet messsages by typing `.greet`").ConfigureAwait(false); }); @@ -245,12 +264,9 @@ namespace NadekoBot.Modules.Administration.Commands .Do(async e => { if (!e.User.ServerPermissions.ManageServer) return; - if (!AnnouncementsDictionary.ContainsKey(e.Server.Id)) - AnnouncementsDictionary.TryAdd(e.Server.Id, new AnnounceControls(e.Server.Id)); + var ann = AnnouncementsDictionary.GetOrAdd(e.Server.Id, new AnnounceControls(e.Server.Id)); - var controls = AnnouncementsDictionary[e.Server.Id]; - - if (controls.ToggleBye(e.Channel.Id)) + if (ann.ToggleBye(e.Channel.Id)) await e.Channel.SendMessage("Bye announcements enabled on this channel.").ConfigureAwait(false); else await e.Channel.SendMessage("Bye announcements disabled.").ConfigureAwait(false); @@ -263,12 +279,11 @@ namespace NadekoBot.Modules.Administration.Commands { if (!e.User.ServerPermissions.ManageServer) return; if (e.GetArg("msg") == null) return; - if (!AnnouncementsDictionary.ContainsKey(e.Server.Id)) - AnnouncementsDictionary.TryAdd(e.Server.Id, new AnnounceControls(e.Server.Id)); + var ann = AnnouncementsDictionary.GetOrAdd(e.Server.Id, new AnnounceControls(e.Server.Id)); - AnnouncementsDictionary[e.Server.Id].ByeText = e.GetArg("msg"); + ann.ByeText = e.GetArg("msg"); await e.Channel.SendMessage("New bye message set.").ConfigureAwait(false); - if (!AnnouncementsDictionary[e.Server.Id].Bye) + if (!ann.Bye) await e.Channel.SendMessage("Enable bye messsages by typing `.bye`.").ConfigureAwait(false); }); @@ -277,15 +292,14 @@ namespace NadekoBot.Modules.Administration.Commands .Do(async e => { if (!e.User.ServerPermissions.ManageServer) return; - if (!AnnouncementsDictionary.ContainsKey(e.Server.Id)) - AnnouncementsDictionary.TryAdd(e.Server.Id, new AnnounceControls(e.Server.Id)); + var ann = AnnouncementsDictionary.GetOrAdd(e.Server.Id, new AnnounceControls(e.Server.Id)); - AnnouncementsDictionary[e.Server.Id].ToggleByePM(); - if (AnnouncementsDictionary[e.Server.Id].ByePM) + + if (ann.ToggleByePM()) await e.Channel.SendMessage("Bye messages will be sent in a PM from now on.\n ⚠ Keep in mind this might fail if the user and the bot have no common servers after the user leaves.").ConfigureAwait(false); else await e.Channel.SendMessage("Bye messages will be sent in a bound channel from now on.").ConfigureAwait(false); - if (!AnnouncementsDictionary[e.Server.Id].Bye) + if (!ann.Bye) await e.Channel.SendMessage("Enable bye messsages by typing `.bye`, and set the bye message using `.byemsg`").ConfigureAwait(false); }); @@ -294,15 +308,14 @@ namespace NadekoBot.Modules.Administration.Commands .Do(async e => { if (!e.User.ServerPermissions.ManageServer) return; - if (!AnnouncementsDictionary.ContainsKey(e.Server.Id)) - AnnouncementsDictionary.TryAdd(e.Server.Id, new AnnounceControls(e.Server.Id)); - AnnouncementsDictionary[e.Server.Id].ToggleGreetPM(); - if (AnnouncementsDictionary[e.Server.Id].GreetPM) + var ann = AnnouncementsDictionary.GetOrAdd(e.Server.Id, new AnnounceControls(e.Server.Id)); + + if (ann.ToggleGreetPM()) await e.Channel.SendMessage("Greet messages will be sent in a PM from now on.").ConfigureAwait(false); else await e.Channel.SendMessage("Greet messages will be sent in a bound channel from now on.").ConfigureAwait(false); - if (!AnnouncementsDictionary[e.Server.Id].Greet) + if (!ann.Greet) await e.Channel.SendMessage("Enable greet messsages by typing `.greet`, and set the greet message using `.greetmsg`").ConfigureAwait(false); }); } diff --git a/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs b/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs index 2865b1b2..55ac9c20 100644 --- a/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs +++ b/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs @@ -130,7 +130,7 @@ namespace NadekoBot.Modules.Games.Commands.Trivia await channel.SendMessage($"☑️ {e.User.Mention} guessed it! The answer was: **{CurrentQuestion.Answer}**").ConfigureAwait(false); if (Users[e.User] != WinRequirement) return; ShouldStopGame = true; - await channel.Send($":exclamation: We have a winner! Its {e.User.Mention}.").ConfigureAwait(false); + await channel.Send($":exclamation: We have a winner! It's {e.User.Mention}.").ConfigureAwait(false); // add points to the winner await FlowersHandler.AddFlowersAsync(e.User, "Won Trivia", 2).ConfigureAwait(false); } diff --git a/NadekoBot/Modules/Help/Commands/HelpCommand.cs b/NadekoBot/Modules/Help/Commands/HelpCommand.cs index 8aedcea9..4458eb77 100644 --- a/NadekoBot/Modules/Help/Commands/HelpCommand.cs +++ b/NadekoBot/Modules/Help/Commands/HelpCommand.cs @@ -11,47 +11,21 @@ namespace NadekoBot.Classes.Help.Commands { internal class HelpCommand : DiscordCommand { - public Func DoFunc() => async e => + public Func HelpFunc() => async e => { - #region OldHelp - /* - string helpstr = "**COMMANDS DO NOT WORK IN PERSONAL MESSAGES**\nOfficial repo: **github.com/Kwoth/NadekoBot/**"; - - string lastCategory = ""; - foreach (var com in client.GetService().AllCommands) - { - if (com.Category != lastCategory) - { - helpstr += "\n`----`**`" + com.Category + "`**`----`\n"; - lastCategory = com.Category; - } - helpstr += PrintCommandHelp(com); - } - helpstr += "\nBot Creator's server: https://discord.gg/0ehQwTK2RBhxEi0X"; - helpstr = helpstr.Replace(NadekoBot.botMention, "@BotName"); - while (helpstr.Length > 2000) - { - var curstr = helpstr.Substring(0, 2000); - await e.User.Send(curstr.Substring(0, curstr.LastIndexOf("\n") + 1)).ConfigureAwait(false); - helpstr = curstr.Substring(curstr.LastIndexOf("\n") + 1) + helpstr.Substring(2000); - await Task.Delay(200).ConfigureAwait(false); - } - */ - #endregion OldHelp - - if (string.IsNullOrWhiteSpace(e.GetArg("command"))) + var comToFind = e.GetArg("command")?.ToLowerInvariant(); + if (string.IsNullOrWhiteSpace(comToFind)) { await e.User.Send(HelpString).ConfigureAwait(false); return; } await Task.Run(async () => { - var comToFind = e.GetArg("command"); - var com = NadekoBot.Client.GetService().AllCommands - .FirstOrDefault(c => c.Text.ToLower().Equals(comToFind)); + .FirstOrDefault(c => c.Text.ToLowerInvariant().Equals(comToFind) || + c.Aliases.Select(a => a.ToLowerInvariant()).Contains(comToFind)); if (com != null) - await e.Channel.SendMessage($"`Help for '{com.Text}':` **{com.Description}**").ConfigureAwait(false); + await e.Channel.SendMessage($"`Help for '{com.Text}':` {com.Description}").ConfigureAwait(false); }).ConfigureAwait(false); }; public static string HelpString => (NadekoBot.IsBot @@ -102,7 +76,7 @@ Version: `{NadekoStats.Instance.BotVersion}`"; .Alias(Module.Prefix + "help", NadekoBot.BotMention + " help", NadekoBot.BotMention + " h", "~h") .Description("Either shows a help for a single command, or PMs you help link if no arguments are specified.\n**Usage**: '-h !m q' or just '-h' ") .Parameter("command", ParameterType.Unparsed) - .Do(DoFunc()); + .Do(HelpFunc()); cgb.CreateCommand(Module.Prefix + "hgit") .Description("Generates the commandlist.md file. **Owner Only!**") .AddCheck(SimpleCheckers.OwnerOnly()) diff --git a/NadekoBot/Modules/Music/MusicModule.cs b/NadekoBot/Modules/Music/MusicModule.cs index bb0acd11..8b1bb252 100644 --- a/NadekoBot/Modules/Music/MusicModule.cs +++ b/NadekoBot/Modules/Music/MusicModule.cs @@ -488,16 +488,6 @@ namespace NadekoBot.Modules.Music }); - //cgb.CreateCommand("info") - // .Description("Prints music info (queued/finished/playing) only to this channel") - // .Do(async e => - // { - // MusicPlayer musicPlayer; - // if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer)) - // return; - // musicPlayer - // }); - cgb.CreateCommand("load") .Description("Loads a playlist under a certain name. \n**Usage**: `!m load classical-1`") .Parameter("name", ParameterType.Unparsed) @@ -553,6 +543,23 @@ namespace NadekoBot.Modules.Music } }); + cgb.CreateCommand("playlists") + .Alias("pls") + .Description("Lists all playlists. Paginated. 20 per page. Default page is 0.\n**Usage**:`!m pls 1`") + .Parameter("num", ParameterType.Optional) + .Do(e => + { + int num = 0; + int.TryParse(e.GetArg("num"), out num); + if (num < 0) + return; + var result = DbHandler.Instance.GetPlaylistData(num); + if (result.Count == 0) + e.Channel.SendMessage($"`No saved playlists found on page {num}`"); + 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} ---```"); + }); + cgb.CreateCommand("goto") .Description("Goes to a specific time in seconds in a song.") .Parameter("time") @@ -589,6 +596,20 @@ namespace NadekoBot.Modules.Music await e.Channel.SendMessage($"`Skipped to {minutes}:{seconds}`").ConfigureAwait(false); }); + + cgb.CreateCommand("getlink") + .Alias("gl") + .Description("Shows a link to the currently playing song.") + .Do(async e => + { + MusicPlayer musicPlayer; + if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer)) + return; + var curSong = musicPlayer.CurrentSong; + if (curSong == null) + return; + await e.Channel.SendMessage($"🎶`Current song:` <{curSong.SongInfo.Query}>"); + }); }); } diff --git a/NadekoBot/Modules/NSFW/NSFWModule.cs b/NadekoBot/Modules/NSFW/NSFWModule.cs index d75ad531..c18d6d09 100644 --- a/NadekoBot/Modules/NSFW/NSFWModule.cs +++ b/NadekoBot/Modules/NSFW/NSFWModule.cs @@ -48,14 +48,7 @@ namespace NadekoBot.Modules.NSFW var tag = e.GetArg("tag")?.Trim() ?? ""; await e.Channel.SendMessage(await SearchHelper.GetGelbooruImageLink(tag).ConfigureAwait(false)).ConfigureAwait(false); }); - cgb.CreateCommand(Prefix + "safebooru") - .Description("Shows a random image from safebooru with a given tag. Tag is optional but preffered. (multiple tags are appended with +)\n**Usage**: ~safebooru yuri+kissing") - .Parameter("tag", ParameterType.Unparsed) - .Do(async e => - { - var tag = e.GetArg("tag")?.Trim() ?? ""; - await e.Channel.SendMessage(await SearchHelper.GetSafebooruImageLink(tag).ConfigureAwait(false)).ConfigureAwait(false); - }); + cgb.CreateCommand(Prefix + "rule34") .Description("Shows a random image from rule34.xx with a given tag. Tag is optional but preffered. (multiple tags are appended with +)\n**Usage**: ~gelbooru yuri+kissing") .Parameter("tag", ParameterType.Unparsed) diff --git a/NadekoBot/Modules/Programming/Commands/HaskellRepl.cs b/NadekoBot/Modules/Programming/Commands/HaskellRepl.cs new file mode 100644 index 00000000..f8c1f78d --- /dev/null +++ b/NadekoBot/Modules/Programming/Commands/HaskellRepl.cs @@ -0,0 +1,92 @@ +using Discord; +using Discord.Commands; +using NadekoBot.Classes; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +/// +/// I have no idea what am i doing +/// +namespace NadekoBot.Modules.Programming.Commands +{ + class HaskellRepl : DiscordCommand + { + ConcurrentQueue> commandQueue = new ConcurrentQueue>(); + + Thread haskellThread; + + public HaskellRepl(DiscordModule module) : base(module) + { + //start haskell interpreter + + haskellThread = new Thread(new ThreadStart(() => + { + var p = Process.Start(new ProcessStartInfo + { + FileName = "stack", //shouldn't use repl, but a Language.Haskell.Interpreter somehow + Arguments = "repl", + UseShellExecute = false, + RedirectStandardInput = true, + RedirectStandardOutput = true, + CreateNoWindow = true, + }); + + Task.Run(async () => + { + while (true) + { + while (commandQueue.Count == 0) + await Task.Delay(100); + + //read from queue + KeyValuePair com; + if (!commandQueue.TryDequeue(out com)) + { + await Task.Delay(100); + continue; + } + //var bytes = Encoding.ASCII.GetBytes(com.Key); + + //send the command to the process + p.StandardInput.WriteLine(com.Key); + + //wait 50 ms for execution + await Task.Delay(50); + + //read everything from the output + var outBuffer = new byte[1500]; + + p.StandardOutput.BaseStream.Read(outBuffer, 0, 1500); + + var outStr = Encoding.ASCII.GetString(outBuffer); + //send to channel + await com.Value.SendMessage($"```hs\nPrelude> {com.Key}\n" + outStr + "\n```"); + } + }); + + })); + haskellThread.Start(); + + } + + internal override void Init(CommandGroupBuilder cgb) + { + cgb.CreateCommand(Module.Prefix + "hs") + .Description("Executes a haskell express with LAMBDABOT") + .Parameter("command", ParameterType.Unparsed) + .Do(e => + { + var com = e.GetArg("command")?.Trim(); + if (string.IsNullOrWhiteSpace(com)) + return; + + //send a command and a channel to the queue + commandQueue.Enqueue(new KeyValuePair(com, e.Channel)); + }); + } + } +} diff --git a/NadekoBot/Modules/Programming/ProgrammingModule.cs b/NadekoBot/Modules/Programming/ProgrammingModule.cs new file mode 100644 index 00000000..feb3c4e2 --- /dev/null +++ b/NadekoBot/Modules/Programming/ProgrammingModule.cs @@ -0,0 +1,26 @@ +using Discord.Modules; +using NadekoBot.Extensions; +using NadekoBot.Modules.Permissions.Classes; +using NadekoBot.Modules.Programming.Commands; + +namespace NadekoBot.Modules.Programming +{ + class ProgrammingModule : DiscordModule + { + public override string Prefix => NadekoBot.Config.CommandPrefixes.Programming; + + public ProgrammingModule() + { + commands.Add(new HaskellRepl(this)); + } + + public override void Install(ModuleManager manager) + { + manager.CreateCommands("", cgb => + { + cgb.AddCheck(PermissionChecker.Instance); + commands.ForEach(c => c.Init(cgb)); + }); + } + } +} diff --git a/NadekoBot/Modules/Searches/Commands/ConverterCommand.cs b/NadekoBot/Modules/Searches/Commands/ConverterCommand.cs index 8d820df4..2383e718 100644 --- a/NadekoBot/Modules/Searches/Commands/ConverterCommand.cs +++ b/NadekoBot/Modules/Searches/Commands/ConverterCommand.cs @@ -92,6 +92,8 @@ namespace NadekoBot.Modules.Searches.Commands } else { + CultureInfo ci = new CultureInfo("en-US"); + Thread.CurrentThread.CurrentCulture = ci; reInitCurrencyConverterTable(); Unit inUnit = currTable.CreateUnit(quantity, from.ToUpperInvariant()); Unit outUnit = inUnit.Convert(currTable.CurrencyCode(to.ToUpperInvariant())); @@ -109,9 +111,16 @@ namespace NadekoBot.Modules.Searches.Commands { if (lastChanged == null || lastChanged.DayOfYear != DateTime.Now.DayOfYear) { - exchangeRateProvider = new WebExchangeRatesProvider(); - currTable = new CurrencyExchangeTable(exchangeRateProvider); - lastChanged = DateTime.Now; + try + { + exchangeRateProvider = new WebExchangeRatesProvider(); + currTable = new CurrencyExchangeTable(exchangeRateProvider); + lastChanged = DateTime.Now; + } + catch + { + Console.WriteLine("Error with the currency download."); + } } } diff --git a/NadekoBot/Modules/Searches/SearchesModule.cs b/NadekoBot/Modules/Searches/SearchesModule.cs index 4f7a3fb4..0d0429d1 100644 --- a/NadekoBot/Modules/Searches/SearchesModule.cs +++ b/NadekoBot/Modules/Searches/SearchesModule.cs @@ -409,6 +409,27 @@ $@"🌍 **Weather for** 【{obj["target"]}】 return; await e.Channel.SendMessage($"https://images.google.com/searchbyimage?image_url={usr.AvatarUrl}").ConfigureAwait(false); }); + + cgb.CreateCommand(Prefix + "revimg") + .Description("Returns a google reverse image search for an image from a link.") + .Parameter("image", ParameterType.Unparsed) + .Do(async e => + { + var imgLink = e.GetArg("image")?.Trim(); + + if (string.IsNullOrWhiteSpace(imgLink)) + return; + await e.Channel.SendMessage($"https://images.google.com/searchbyimage?image_url={imgLink}").ConfigureAwait(false); + }); + + cgb.CreateCommand(Prefix + "safebooru") + .Description("Shows a random image from safebooru with a given tag. Tag is optional but preffered. (multiple tags are appended with +)\n**Usage**: ~safebooru yuri+kissing") + .Parameter("tag", ParameterType.Unparsed) + .Do(async e => + { + var tag = e.GetArg("tag")?.Trim() ?? ""; + await e.Channel.SendMessage(await SearchHelper.GetSafebooruImageLink(tag).ConfigureAwait(false)).ConfigureAwait(false); + }); }); } } diff --git a/NadekoBot/NadekoBot.cs b/NadekoBot/NadekoBot.cs index df556c46..6b90f6d4 100644 --- a/NadekoBot/NadekoBot.cs +++ b/NadekoBot/NadekoBot.cs @@ -200,7 +200,6 @@ namespace NadekoBot await Client.Connect(Creds.Token).ConfigureAwait(false); IsBot = true; } - Console.WriteLine(NadekoBot.Client.CurrentUser.Id); } catch (Exception ex) { @@ -213,7 +212,7 @@ namespace NadekoBot return; } - //await Task.Delay(90000).ConfigureAwait(false); + await Task.Delay(2000).ConfigureAwait(false); Console.WriteLine("-----------------"); Console.WriteLine(await NadekoStats.Instance.GetStats().ConfigureAwait(false)); Console.WriteLine("-----------------"); diff --git a/NadekoBot/NadekoBot.csproj b/NadekoBot/NadekoBot.csproj index c1036806..a6a84cfa 100644 --- a/NadekoBot/NadekoBot.csproj +++ b/NadekoBot/NadekoBot.csproj @@ -124,6 +124,9 @@ + + + diff --git a/NadekoBot/_Models/DataModels/AnnouncementModel.cs b/NadekoBot/_Models/DataModels/AnnouncementModel.cs index 534daf24..c4103dad 100644 --- a/NadekoBot/_Models/DataModels/AnnouncementModel.cs +++ b/NadekoBot/_Models/DataModels/AnnouncementModel.cs @@ -15,5 +15,6 @@ namespace NadekoBot.DataModels [JsonProperty("byeChannel")] public long ByeChannelId { get; set; } = 0; public string ByeText { get; set; } = "%user% has left the server."; + public bool DeleteGreetMessages { get; set; } = true; } } diff --git a/README.md b/README.md index f68895ed..69af3760 100644 --- a/README.md +++ b/README.md @@ -16,9 +16,8 @@ When you clone the project, make sure to run `git submodule init` and `git submo **This is how the credentials.json should look like:** ```json { - "Username":"bot_email", "BotId": 123123123123, - "Password":"bot_password", + "Token":"Bot.Token", "GoogleAPIKey":"google_api_key", "OwnerIds":[123123123123, 123123123123], "TrelloAppKey": "your_trello_app_key (optional)", @@ -52,6 +51,7 @@ Next to your exe you must also have a data folder in which there is config.json "UserBlacklist": [] } ``` +- http://discord.kongslien.net/guide.html <- to make a bot account and get the `Token` - BotId and OwnerIds are **NOT** names of the owner and the bot. If you do not know the id of your bot, put 2 random numbers in those fields, run the bot and do `.uid @MyBotName` - that will give you your bot\_id, do the same for yourself `.uid @MyName` and copy the numbers in their respective fields. - For google api key, you need to enable URL shortner, Youtube video search **and custom search** in the [dev console](https://console.developers.google.com/). - For the Soundcloud Api key you need a Soundcloud account. You need to create a new app on http://soundcloud.com/you/apps/new and after that go here http://soundcloud.com/you/apps click on the name of your created your app and copy the Client ID. Paste it into credentials.json.