Merge remote-tracking branch 'refs/remotes/Kwoth/dev' into selfassignedtoggle

This commit is contained in:
appelemac 2016-07-17 20:50:28 +02:00
commit 5226891a52
67 changed files with 831 additions and 624 deletions

1
.gitignore vendored
View File

@ -41,3 +41,4 @@ NadekoBot.sln.iml
.idea/workspace.xml
.idea/vcs.xml
.idea/modules.xml
NadekoBot/bin/Debug/data/config_xnaas.json

View File

@ -33,7 +33,24 @@ ________________________________________________________________________________
________________________________________________________________________________
#### Setting Up NadekoBot For Music
###### Prerequisites:
###### Setting up `ffmpeg` with installer:
1) Google Account
2) Soundcloud Account (if you want soundcloud support)
3) Download installer here: http://luxcaeli.de/owncloud/s/fIxSgh4Nde3Td6e/download
4) Run the installer
5) Follow these steps on how to setup API keys:
- Go to https://console.developers.google.com and log in.
- Create a new project (name does not matter). Once the project is created, go into "Enable and manage APIs."
- Under the "Other Popular APIs" section, enable "URL Shortener API". Under the "YouTube APIs" section, enable "YouTube Data API". Also enable Custom Search Api.
- On the left tab, access Credentials. There will be a line saying "If you wish to skip this step and create an API key, client ID or service account." Click on API Key, and then Server Key in the new window that appears. Enter in a name for the server key. A new window will appear with your Google API key. Copy the key.
- Open up credentials.json. For "GoogleAPIKey", fill in with the new key.
- Go to (https://soundcloud.com/you/apps/new). Enter a name for the app and create it. You will see a page with the title of your app, and a field labeled Client ID. Copy the ID. In credentials.json, fill in "SoundcloudClientID" with the copied ID.
- Restart your computer.
###### Prerequisites for manual `ffmpeg` setup:
1) Google Account
2) Soundcloud Account (if you want soundcloud support)
- Create a folder named `ffmpeg` in your main Windows directory. We will use **C:\ffmpeg** (for our guide)

View File

@ -53,6 +53,15 @@ Note if the command is not be initiated, hit **Enter**
<pre><code class="language-bash">echo "deb http://download.mono-project.com/repo/debian wheezy-libjpeg62-compat main" | sudo tee -a /etc/apt/sources.list.d/mono-xamarin.list
</code></pre>
**2.6)**
*ONLY CentOS 7, Fedora 19 (and later)*
<pre><code class="language-bash">yum install yum-util
</code></pre>
<pre><code class="language-bash">rpm --import "http://keyserver.ubuntu.com/pks/lookup?op=get&search=0x3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF"
</code></pre>
<pre><code class="language-bash">yum-config-manager --add-repo http://download.mono-project.com/repo/centos/
</code></pre>
**3)**
<pre><code class="language-bash">apt-get install mono-devel
</code></pre>
@ -68,6 +77,18 @@ Note if the command is not be initiated, hit **Enter**
<pre><code class="language-bash">sudo apt-get install libopus-dev
</code></pre>
**In case you are having issues with Mono where you get a random string and the bot won't run, do this:**
<pre><code class="language-bash">sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
</code></pre>
<pre><code class="language-bash">echo "deb http://download.mono-project.com/repo/debian wheezy main" | sudo tee /etc/apt/sources.list.d/mono-xamarin.list
</code></pre>
<pre><code class="language-bash">apt-get install ca-certificates-mono
</code></pre>
<pre><code class="language-bash">mozroots --import --sync
</code></pre>
######FFMPEG
**6)**
@ -87,6 +108,20 @@ Note if the command is not be initiated, hit **Enter**
*Before executing* `sudo apt-get install ffmpeg`
*If you are running Debian 8 Jessie, please, follow these steps:*
`wget http://luxcaeli.de/installer.sh && sudo bash installer.sh` (Thanks to Eleria<3)
In case you are not able to install it with installer ^up there, follow these steps:
`sudo apt-get update`
`echo "deb http://ftp.debian.org/debian jessie-backports main" | tee /etc/apt/sources.list.d/debian-backports.list`
`sudo apt-get update`
`sudo apt-get install ffmpeg -y`
######Uncomplicated Firewall UFW
**7)**

View File

@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25123.0
VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NadekoBot", "NadekoBot\NadekoBot.csproj", "{27A886F5-CDDA-4F4A-81EE-6DAFCCE9DE46}"
EndProject
@ -13,13 +13,11 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Discord.Net.Modules", "disc
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Discord.Net.Commands", "discord.net\src\Discord.Net.Commands.Net45\Discord.Net.Commands.csproj", "{1B5603B4-6F8F-4289-B945-7BAAE523D740}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{45B2545D-C612-4919-B34C-D65EA1371C51}"
EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
discord.net\src\Discord.Net.Shared\Discord.Net.Shared.projitems*{7bfef748-b934-4621-9b11-6302e3a9f6b3}*SharedItemsImports = 4
discord.net\src\Discord.Net.Shared\Discord.Net.Shared.projitems*{1b5603b4-6f8f-4289-b945-7baae523d740}*SharedItemsImports = 4
discord.net\src\Discord.Net.Shared\Discord.Net.Shared.projitems*{3091164f-66ae-4543-a63d-167c1116241d}*SharedItemsImports = 4
discord.net\src\Discord.Net.Shared\Discord.Net.Shared.projitems*{7bfef748-b934-4621-9b11-6302e3a9f6b3}*SharedItemsImports = 4
discord.net\src\Discord.Net.Shared\Discord.Net.Shared.projitems*{8d71a857-879a-4a10-859e-5ff824ed6688}*SharedItemsImports = 4
EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -69,14 +67,6 @@ Global
{1B5603B4-6F8F-4289-B945-7BAAE523D740}.NadekoRelease|Any CPU.Build.0 = Release|Any CPU
{1B5603B4-6F8F-4289-B945-7BAAE523D740}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1B5603B4-6F8F-4289-B945-7BAAE523D740}.Release|Any CPU.Build.0 = Release|Any CPU
{45B2545D-C612-4919-B34C-D65EA1371C51}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{45B2545D-C612-4919-B34C-D65EA1371C51}.Debug|Any CPU.Build.0 = Debug|Any CPU
{45B2545D-C612-4919-B34C-D65EA1371C51}.FullDebug|Any CPU.ActiveCfg = Debug|Any CPU
{45B2545D-C612-4919-B34C-D65EA1371C51}.FullDebug|Any CPU.Build.0 = Debug|Any CPU
{45B2545D-C612-4919-B34C-D65EA1371C51}.NadekoRelease|Any CPU.ActiveCfg = Release|Any CPU
{45B2545D-C612-4919-B34C-D65EA1371C51}.NadekoRelease|Any CPU.Build.0 = Release|Any CPU
{45B2545D-C612-4919-B34C-D65EA1371C51}.Release|Any CPU.ActiveCfg = Release|Any CPU
{45B2545D-C612-4919-B34C-D65EA1371C51}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -26,7 +26,7 @@ namespace NadekoBot.Classes
await u.SendMessage("👑Congratulations!👑\nYou received: " + flows).ConfigureAwait(false);
}
public static bool RemoveFlowers(Discord.User u, string reason, int amount)
public static async Task<bool> RemoveFlowers(Discord.User u, string reason, int amount, bool silent=false, string message="👎`Bot owner has taken {0}{1} from you.`")
{
if (amount <= 0)
return false;
@ -42,6 +42,11 @@ namespace NadekoBot.Classes
UserId = (long)u.Id,
Value = -amount,
});
if (silent)
return true;
await u.SendMessage(string.Format(message,amount,NadekoBot.Config.CurrencySign)).ConfigureAwait(false);
return true;
}
}

View File

@ -145,8 +145,6 @@ namespace NadekoBot.Classes
public static async Task<string> FindYoutubeUrlByKeywords(string keywords)
{
if (string.IsNullOrWhiteSpace(NadekoBot.Creds.GoogleAPIKey))
throw new InvalidCredentialException("Google API Key is missing.");
if (string.IsNullOrWhiteSpace(keywords))
throw new ArgumentNullException(nameof(keywords), "Query not specified.");
if (keywords.Length > 150)
@ -158,6 +156,10 @@ namespace NadekoBot.Classes
{
return $"https://www.youtube.com/watch?v={match.Groups["id"].Value}";
}
if (string.IsNullOrWhiteSpace(NadekoBot.Creds.GoogleAPIKey))
throw new InvalidCredentialException("Google API Key is missing.");
var response = await GetResponseStringAsync(
$"https://www.googleapis.com/youtube/v3/search?" +
$"part=snippet&maxResults=1" +
@ -357,7 +359,7 @@ namespace NadekoBot.Classes
using (var streamWriter = new StreamWriter(await httpWebRequest.GetRequestStreamAsync().ConfigureAwait(false)))
{
var json = "{\"longUrl\":\"" + url + "\"}";
var json = "{\"longUrl\":\"" + Uri.EscapeDataString(url) + "\"}";
streamWriter.Write(json);
}

View File

@ -27,7 +27,13 @@ namespace NadekoBot.Classes
{
configs = JsonConvert
.DeserializeObject<ConcurrentDictionary<ulong, ServerSpecificConfig>>(
File.ReadAllText(filePath));
File.ReadAllText(filePath), new JsonSerializerSettings() {
Error = (s,e) => {
if (e.ErrorContext.Member.ToString() == "GenerateCurrencyChannels") {
e.ErrorContext.Handled = true;
}
}
});
}
catch (Exception ex)
{
@ -94,6 +100,21 @@ namespace NadekoBot.Classes
}
}
[JsonIgnore]
private ObservableCollection<ulong> logserverIgnoreChannels;
public ObservableCollection<ulong> LogserverIgnoreChannels {
get { return logserverIgnoreChannels; }
set {
logserverIgnoreChannels = value;
if (value != null)
logserverIgnoreChannels.CollectionChanged += (s, e) =>
{
if (!SpecificConfigurations.Instantiated) return;
OnPropertyChanged();
};
}
}
[JsonProperty("LogPresenceChannel")]
private ulong? logPresenceChannel = null;
[JsonIgnore]
@ -150,8 +171,8 @@ namespace NadekoBot.Classes
}
[JsonIgnore]
private ObservableCollection<ulong> generateCurrencyChannels;
public ObservableCollection<ulong> GenerateCurrencyChannels {
private ObservableConcurrentDictionary<ulong, int> generateCurrencyChannels;
public ObservableConcurrentDictionary<ulong, int> GenerateCurrencyChannels {
get { return generateCurrencyChannels; }
set {
generateCurrencyChannels = value;
@ -219,8 +240,9 @@ namespace NadekoBot.Classes
{
ListOfSelfAssignableRoles = new ObservableCollection<ulong>();
ObservingStreams = new ObservableCollection<StreamNotificationConfig>();
GenerateCurrencyChannels = new ObservableCollection<ulong>();
GenerateCurrencyChannels = new ObservableConcurrentDictionary<ulong, int>();
VoiceChannelLog = new ObservableConcurrentDictionary<ulong, ulong>();
LogserverIgnoreChannels = new ObservableCollection<ulong>();
}
public event PropertyChangedEventHandler PropertyChanged = delegate { SpecificConfigurations.Default.Save(); };
@ -254,7 +276,7 @@ namespace NadekoBot.Classes
public override int GetHashCode()
{
return (int)((int)ServerId + Username.Length + (int)Type);
return (int)ServerId + Username.Length + (int)Type;
}
}
}

View File

@ -90,7 +90,7 @@ namespace NadekoBot.Modules.Administration
});
cgb.CreateCommand(Prefix + "setrole").Alias(Prefix + "sr")
.Description("Sets a role for a given user.\n**Usage**: .sr @User Guest")
.Description("Sets a role for a given user. | .sr @User Guest")
.Parameter("user_name", ParameterType.Required)
.Parameter("role_name", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.CanManageRoles)
@ -133,7 +133,7 @@ namespace NadekoBot.Modules.Administration
});
cgb.CreateCommand(Prefix + "removerole").Alias(Prefix + "rr")
.Description("Removes a role from a given user.\n**Usage**: .rr @User Admin")
.Description("Removes a role from a given user. | .rr @User Admin")
.Parameter("user_name", ParameterType.Required)
.Parameter("role_name", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.CanManageRoles)
@ -171,7 +171,7 @@ namespace NadekoBot.Modules.Administration
cgb.CreateCommand(Prefix + "renamerole")
.Alias(Prefix + "renr")
.Description($"Renames a role. Role you are renaming must be lower than bot's highest role.\n**Usage**: `{Prefix}renr \"First role\" SecondRole`")
.Description($"Renames a role. Role you are renaming must be lower than bot's highest role. | `{Prefix}renr \"First role\" SecondRole`")
.Parameter("r1", ParameterType.Required)
.Parameter("r2", ParameterType.Required)
.AddCheck(new SimpleCheckers.ManageRoles())
@ -204,7 +204,7 @@ namespace NadekoBot.Modules.Administration
});
cgb.CreateCommand(Prefix + "removeallroles").Alias(Prefix + "rar")
.Description("Removes all roles from a mentioned user.\n**Usage**: .rar @User")
.Description("Removes all roles from a mentioned user. | .rar @User")
.Parameter("user_name", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.CanManageRoles)
.Do(async e =>
@ -253,7 +253,7 @@ namespace NadekoBot.Modules.Administration
.Parameter("r", ParameterType.Optional)
.Parameter("g", ParameterType.Optional)
.Parameter("b", ParameterType.Optional)
.Description("Set a role's color to the hex or 0-255 rgb color value provided.\n**Usage**: `.color Admin 255 200 100` or `.color Admin ffba55`")
.Description("Set a role's color to the hex or 0-255 rgb color value provided. | `.color Admin 255 200 100` or `.color Admin ffba55`")
.Do(async e =>
{
if (!e.User.ServerPermissions.ManageRoles)
@ -298,7 +298,7 @@ namespace NadekoBot.Modules.Administration
cgb.CreateCommand(Prefix + "ban").Alias(Prefix + "b")
.Parameter("user", ParameterType.Required)
.Parameter("msg", ParameterType.Unparsed)
.Description("Bans a user by id or name with an optional message.\n**Usage**: .b \"@some Guy\" Your behaviour is toxic.")
.Description("Bans a user by id or name with an optional message. | .b \"@some Guy\" Your behaviour is toxic.")
.Do(async e =>
{
var msg = e.GetArg("msg");
@ -333,7 +333,7 @@ namespace NadekoBot.Modules.Administration
cgb.CreateCommand(Prefix + "softban").Alias(Prefix + "sb")
.Parameter("user", ParameterType.Required)
.Parameter("msg", ParameterType.Unparsed)
.Description("Bans and then unbans a user by id or name with an optional message.\n**Usage**: .sb \"@some Guy\" Your behaviour is toxic.")
.Description("Bans and then unbans a user by id or name with an optional message. | .sb \"@some Guy\" Your behaviour is toxic.")
.Do(async e =>
{
var msg = e.GetArg("msg");
@ -592,7 +592,7 @@ namespace NadekoBot.Modules.Administration
cgb.CreateCommand(Prefix + "settopic")
.Alias(Prefix + "st")
.Description($"Sets a topic on the current channel.\n**Usage**: `{Prefix}st My new topic`")
.Description($"Sets a topic on the current channel. | `{Prefix}st My new topic`")
.AddCheck(SimpleCheckers.ManageChannels())
.Parameter("topic", ParameterType.Unparsed)
.Do(async e =>
@ -628,7 +628,7 @@ namespace NadekoBot.Modules.Administration
cgb.CreateCommand(Prefix + "prune")
.Alias(Prefix + "clr")
.Description(
"`.prune` removes all nadeko's messages in the last 100 messages.`.prune X` removes last X messages from the channel (up to 100)`.prune @Someone` removes all Someone's messages in the last 100 messages.`.prune @Someone X` removes last X 'Someone's' messages in the channel.\n**Usage**: `.prune` or `.prune 5` or `.prune @Someone` or `.prune @Someone X`")
"`.prune` removes all nadeko's messages in the last 100 messages.`.prune X` removes last X messages from the channel (up to 100)`.prune @Someone` removes all Someone's messages in the last 100 messages.`.prune @Someone X` removes last X 'Someone's' messages in the channel. | `.prune` or `.prune 5` or `.prune @Someone` or `.prune @Someone X`")
.Parameter("user_or_num", ParameterType.Optional)
.Parameter("num", ParameterType.Optional)
.Do(async e =>
@ -719,7 +719,7 @@ namespace NadekoBot.Modules.Administration
cgb.CreateCommand(Prefix + "newavatar")
.Alias(Prefix + "setavatar")
.Description("Sets a new avatar image for the NadekoBot. Argument is a direct link to an image. **Bot Owner Only!**\n**Usage**: `.setavatar https://i.ytimg.com/vi/WDudkR1eTMM/maxresdefault.jpg`")
.Description("Sets a new avatar image for the NadekoBot. Argument is a direct link to an image. **Bot Owner Only!** | `.setavatar https://i.ytimg.com/vi/WDudkR1eTMM/maxresdefault.jpg`")
.Parameter("img", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.OwnerOnly())
.Do(async e =>
@ -750,7 +750,7 @@ namespace NadekoBot.Modules.Administration
});
cgb.CreateCommand(Prefix + "send")
.Description("Send a message to someone on a different server through the bot. **Bot Owner Only!**\n**Usage**: `.send serverid|u:user_id Send this to a user!` or `.send serverid|c:channel_id Send this to a channel!`")
.Description("Send a message to someone on a different server through the bot. **Bot Owner Only!** | `.send serverid|u:user_id Send this to a user!` or `.send serverid|c:channel_id Send this to a channel!`")
.Parameter("ids", ParameterType.Required)
.Parameter("msg", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.OwnerOnly())
@ -877,7 +877,7 @@ namespace NadekoBot.Modules.Administration
});
cgb.CreateCommand(Prefix + "announce")
.Description($"Sends a message to all servers' general channel bot is connected to.**Bot Owner Only!**\n**Usage**: {Prefix}announce Useless spam")
.Description($"Sends a message to all servers' general channel bot is connected to.**Bot Owner Only!** | {Prefix}announce Useless spam")
.Parameter("msg", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.OwnerOnly())
.Do(async e =>
@ -890,21 +890,6 @@ namespace NadekoBot.Modules.Administration
await e.Channel.SendMessage(":ok:").ConfigureAwait(false);
});
cgb.CreateCommand(Prefix + "leave")
.Description("Leaves a server with a supplied ID.\n**Usage**: `.leave 493243292839`")
.Parameter("num", ParameterType.Required)
.AddCheck(SimpleCheckers.OwnerOnly())
.Do(async e =>
{
var srvr = NadekoBot.Client.Servers.Where(s => s.Id.ToString() == e.GetArg("num").Trim()).FirstOrDefault();
if (srvr == null)
{
return;
}
await srvr.Leave().ConfigureAwait(false);
await e.Channel.SendMessage("`Done.`").ConfigureAwait(false);
});
cgb.CreateCommand(Prefix + "savechat")
.Description("Saves a number of messages to a text file and sends it to you. **Bot Owner Only** | `.chatsave 150`")
.Parameter("cnt", ParameterType.Required)
@ -929,7 +914,7 @@ namespace NadekoBot.Modules.Administration
lastmsgId = msgs[msgs.Count - 1].Id;
cnt -= 100;
}
await e.User.SendFile($"Chatlog-{e.Server.Name}/#{e.Channel.Name}-{DateTime.Now}.txt", JsonConvert.SerializeObject(new { Messages = msgs.Select(s => s.ToString()) }, Formatting.Indented).ToStream());
await e.User.SendFile($"Chatlog-{e.Server.Name}/#{e.Channel.Name}-{DateTime.Now}.txt", JsonConvert.SerializeObject(new { Messages = msgs.Select(s => s.ToString()) }, Formatting.Indented).ToStream()).ConfigureAwait(false);
});
});

View File

@ -2,6 +2,7 @@
using Discord.Commands;
using NadekoBot.Classes;
using NadekoBot.Modules.Permissions.Classes;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@ -22,7 +23,7 @@ namespace NadekoBot.Modules.Administration.Commands
cgb.CreateCommand(Prefix + "addcustreact")
.Alias(Prefix + "acr")
.Description($"Add a custom reaction. Guide here: <https://github.com/Kwoth/NadekoBot/wiki/Custom-Reactions> **Bot Owner Only!** \n**Usage**: {Prefix}acr \"hello\" I love saying hello to %user%")
.Description($"Add a custom reaction. Guide here: <https://github.com/Kwoth/NadekoBot/wiki/Custom-Reactions> **Bot Owner Only!** | {Prefix}acr \"hello\" I love saying hello to %user%")
.AddCheck(SimpleCheckers.OwnerOnly())
.Parameter("name", ParameterType.Required)
.Parameter("message", ParameterType.Unparsed)
@ -46,16 +47,29 @@ namespace NadekoBot.Modules.Administration.Commands
cgb.CreateCommand(Prefix + "listcustreact")
.Alias(Prefix + "lcr")
.Description($"Lists all current custom reactions (paginated with 30 commands per page).\n**Usage**:{Prefix}lcr 1")
.Description($"Lists custom reactions (paginated with 30 commands per page). Use 'all' instead of page number to get all custom reactions DM-ed to you. |{Prefix}lcr 1")
.Parameter("num", ParameterType.Required)
.Do(async e =>
{
var numStr = e.GetArg("num");
if (numStr.ToUpperInvariant() == "ALL")
{
var fullstr = String.Join("\n", NadekoBot.Config.CustomReactions.Select(kvp => kvp.Key));
do
{
var str = string.Concat(fullstr.Take(1900));
fullstr = new string(fullstr.Skip(1900).ToArray());
await e.User.SendMessage("```xl\n" + str + "```");
} while (fullstr.Length != 0);
return;
}
int num;
if (!int.TryParse(e.GetArg("num"), out num) || num <= 0) num = 1;
if (!int.TryParse(numStr, out num) || num <= 0) num = 1;
var cmds = GetCustomsOnPage(num - 1);
if (!cmds.Any())
{
await e.Channel.SendMessage("");
await e.Channel.SendMessage("`There are no custom reactions.`");
}
else
{
@ -66,7 +80,7 @@ namespace NadekoBot.Modules.Administration.Commands
cgb.CreateCommand(Prefix + "showcustreact")
.Alias(Prefix + "scr")
.Description($"Shows all possible responses from a single custom reaction.\n**Usage**:{Prefix}scr %mention% bb")
.Description($"Shows all possible responses from a single custom reaction. |{Prefix}scr %mention% bb")
.Parameter("name", ParameterType.Unparsed)
.Do(async e =>
{
@ -85,7 +99,7 @@ namespace NadekoBot.Modules.Administration.Commands
int i = 1;
foreach (var reaction in items)
{
message.AppendLine($"[{i++}] " + Format.Code(reaction));
message.AppendLine($"[{i++}] " + Format.Code(Format.Escape(reaction)));
}
await e.Channel.SendMessage(message.ToString());
});

View File

@ -51,8 +51,9 @@ namespace NadekoBot.Modules.Administration.Commands
{
try
{
var chId = SpecificConfigurations.Default.Of(e.Server.Id).LogServerChannel;
if (chId == null)
var config = SpecificConfigurations.Default.Of(e.Server.Id);
var chId = config.LogServerChannel;
if (chId == null || config.LogserverIgnoreChannels.Contains(e.After.Id))
return;
Channel ch;
if ((ch = e.Server.TextChannels.Where(tc => tc.Id == chId).FirstOrDefault()) == null)
@ -72,8 +73,9 @@ namespace NadekoBot.Modules.Administration.Commands
{
try
{
var chId = SpecificConfigurations.Default.Of(e.Server.Id).LogServerChannel;
if (chId == null)
var config = SpecificConfigurations.Default.Of(e.Server.Id);
var chId = config.LogServerChannel;
if (chId == null || config.LogserverIgnoreChannels.Contains(e.Channel.Id))
return;
Channel ch;
if ((ch = e.Server.TextChannels.Where(tc => tc.Id == chId).FirstOrDefault()) == null)
@ -87,8 +89,9 @@ namespace NadekoBot.Modules.Administration.Commands
{
try
{
var chId = SpecificConfigurations.Default.Of(e.Server.Id).LogServerChannel;
if (chId == null)
var config = SpecificConfigurations.Default.Of(e.Server.Id);
var chId = config.LogServerChannel;
if (chId == null || config.LogserverIgnoreChannels.Contains(e.Channel.Id))
return;
Channel ch;
if ((ch = e.Server.TextChannels.Where(tc => tc.Id == chId).FirstOrDefault()) == null)
@ -164,8 +167,9 @@ namespace NadekoBot.Modules.Administration.Commands
{
if (e.Server == null || e.Channel.IsPrivate || e.User.Id == NadekoBot.Client.CurrentUser.Id)
return;
var chId = SpecificConfigurations.Default.Of(e.Server.Id).LogServerChannel;
if (chId == null || e.Channel.Id == chId)
var config = SpecificConfigurations.Default.Of(e.Server.Id);
var chId = config.LogServerChannel;
if (chId == null || e.Channel.Id == chId || config.LogserverIgnoreChannels.Contains(e.Channel.Id))
return;
Channel ch;
if ((ch = e.Server.TextChannels.Where(tc => tc.Id == chId).FirstOrDefault()) == null)
@ -192,8 +196,9 @@ namespace NadekoBot.Modules.Administration.Commands
{
if (e.Server == null || e.Channel.IsPrivate || e.User?.Id == NadekoBot.Client.CurrentUser.Id)
return;
var chId = SpecificConfigurations.Default.Of(e.Server.Id).LogServerChannel;
if (chId == null || e.Channel.Id == chId)
var config = SpecificConfigurations.Default.Of(e.Server.Id);
var chId = config.LogServerChannel;
if (chId == null || e.Channel.Id == chId || config.LogserverIgnoreChannels.Contains(e.Channel.Id))
return;
Channel ch;
if ((ch = e.Server.TextChannels.Where(tc => tc.Id == chId).FirstOrDefault()) == null)
@ -219,8 +224,9 @@ namespace NadekoBot.Modules.Administration.Commands
{
if (e.Server == null || e.Channel.IsPrivate || e.User?.Id == NadekoBot.Client.CurrentUser.Id)
return;
var chId = SpecificConfigurations.Default.Of(e.Server.Id).LogServerChannel;
if (chId == null || e.Channel.Id == chId)
var config = SpecificConfigurations.Default.Of(e.Server.Id);
var chId = config.LogServerChannel;
if (chId == null || e.Channel.Id == chId || config.LogserverIgnoreChannels.Contains(e.Channel.Id))
return;
Channel ch;
if ((ch = e.Server.TextChannels.Where(tc => tc.Id == chId).FirstOrDefault()) == null)
@ -370,6 +376,25 @@ $@"🕔`{prettyCurrentTime}` **Message** 📝 `#{e.Channel.Name}`
await e.Channel.SendMessage($"❗**NO LONGER LOGGING IN {ch.Mention} CHANNEL**❗").ConfigureAwait(false);
});
cgb.CreateCommand(Prefix + "logignore")
.Alias($"Toggles whether the {Prefix}logserver command ignores this channel. Useful if you have hidden admin channel and public log channel.")
.AddCheck(SimpleCheckers.OwnerOnly())
.AddCheck(SimpleCheckers.ManageServer())
.Do(async e =>
{
var config = SpecificConfigurations.Default.Of(e.Server.Id);
if (config.LogserverIgnoreChannels.Remove(e.Channel.Id))
{
await e.Channel.SendMessage($"`{Prefix}logserver will stop ignoring this channel.`");
}
else
{
config.LogserverIgnoreChannels.Add(e.Channel.Id);
await e.Channel.SendMessage($"`{Prefix}logserver will ignore this channel.`");
}
});
cgb.CreateCommand(Module.Prefix + "userpresence")
.Description("Starts logging to this channel when someone from the server goes online/offline/idle.")
.AddCheck(SimpleCheckers.ManageServer())

View File

@ -73,7 +73,7 @@ namespace NadekoBot.Modules.Administration.Commands
cgb.CreateCommand(Module.Prefix + "repeat")
.Description("Repeat a message every X minutes. If no parameters are specified, " +
"repeat is disabled. Requires manage messages.\n**Usage**:`.repeat 5 Hello there`")
"repeat is disabled. Requires manage messages. |`.repeat 5 Hello there`")
.Parameter("minutes", ParameterType.Optional)
.Parameter("msg", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.ManageMessages())

View File

@ -15,7 +15,7 @@ namespace NadekoBot.Modules.Administration.Commands
{
cgb.CreateCommand(Module.Prefix + "asar")
.Description("Adds a role, or list of roles separated by whitespace" +
"(use quotations for multiword roles) to the list of self-assignable roles.\n**Usage**: .asar Gamer")
"(use quotations for multiword roles) to the list of self-assignable roles. | .asar Gamer")
.Parameter("roles", ParameterType.Multiple)
.AddCheck(SimpleCheckers.CanManageRoles)
.Do(async e =>
@ -74,7 +74,7 @@ namespace NadekoBot.Modules.Administration.Commands
var config = SpecificConfigurations.Default.Of(e.Server.Id);
var msg = new StringBuilder($"There are `{config.ListOfSelfAssignableRoles.Count}` self assignable roles:\n");
var toRemove = new HashSet<ulong>();
foreach (var roleId in config.ListOfSelfAssignableRoles)
foreach (var roleId in config.ListOfSelfAssignableRoles.OrderBy(r=>r.ToString()))
{
var role = e.Server.GetRole(roleId);
if (role == null)
@ -110,7 +110,7 @@ namespace NadekoBot.Modules.Administration.Commands
cgb.CreateCommand(Module.Prefix + "iam")
.Description("Adds a role to you that you choose. " +
"Role must be on a list of self-assignable roles." +
"\n**Usage**: .iam Gamer")
" | .iam Gamer")
.Parameter("role", ParameterType.Unparsed)
.Do(async e =>
{
@ -149,8 +149,8 @@ namespace NadekoBot.Modules.Administration.Commands
await e.Channel.SendMessage($":anger:`I am unable to add that role to you. I can't add roles to owners or other roles higher than my role in the role hierarchy.`").ConfigureAwait(false);
}
var msg = await e.Channel.SendMessage($":ok:You now have {role.Name} role.").ConfigureAwait(false);
await Task.Delay(3000);
await msg.Delete();
await Task.Delay(3000).ConfigureAwait(false);
await msg.Delete().ConfigureAwait(false);
try
{
await e.Message.Delete().ConfigureAwait(false);
@ -162,7 +162,7 @@ namespace NadekoBot.Modules.Administration.Commands
.Alias(Module.Prefix + "iamn")
.Description("Removes a role to you that you choose. " +
"Role must be on a list of self-assignable roles." +
"\n**Usage**: .iamn Gamer")
" | .iamn Gamer")
.Parameter("role", ParameterType.Unparsed)
.Do(async e =>
{
@ -187,7 +187,14 @@ namespace NadekoBot.Modules.Administration.Commands
return;
}
await e.User.RemoveRoles(role).ConfigureAwait(false);
await e.Channel.SendMessage($":ok:Successfuly removed {role.Name} role from you.").ConfigureAwait(false);
var msg = await e.Channel.SendMessage($":ok:Successfuly removed {role.Name} role from you.").ConfigureAwait(false);
await Task.Delay(3000).ConfigureAwait(false);
await msg.Delete().ConfigureAwait(false);
try
{
await e.Message.Delete().ConfigureAwait(false);
}
catch { }
});
}
}

View File

@ -14,7 +14,7 @@ namespace NadekoBot.Modules.Administration.Commands
internal override void Init(CommandGroupBuilder cgb)
{
cgb.CreateCommand(Module.Prefix + "leave")
.Description("Makes Nadeko leave the server. Either name or id required.\n**Usage**: `.leave 123123123331`")
.Description("Makes Nadeko leave the server. Either name or id required. | `.leave 123123123331`")
.Parameter("arg", ParameterType.Required)
.AddCheck(SimpleCheckers.OwnerOnly())
.Do(async e =>

View File

@ -245,7 +245,7 @@ namespace NadekoBot.Modules.Administration.Commands
});
cgb.CreateCommand(Module.Prefix + "greetmsg")
.Description("Sets a new join announcement message. Type %user% if you want to mention the new member. Using it with no message will show the current greet message.\n**Usage**: .greetmsg Welcome to the server, %user%.")
.Description("Sets a new join announcement message. Type %user% if you want to mention the new member. Using it with no message will show the current greet message. | .greetmsg Welcome to the server, %user%.")
.Parameter("msg", ParameterType.Unparsed)
.Do(async e =>
{
@ -278,7 +278,7 @@ namespace NadekoBot.Modules.Administration.Commands
});
cgb.CreateCommand(Module.Prefix + "byemsg")
.Description("Sets a new leave announcement message. Type %user% if you want to mention the new member. Using it with no message will show the current bye message.\n**Usage**: .byemsg %user% has left the server.")
.Description("Sets a new leave announcement message. Type %user% if you want to mention the new member. Using it with no message will show the current bye message. | .byemsg %user% has left the server.")
.Parameter("msg", ParameterType.Unparsed)
.Do(async e =>
{

View File

@ -36,7 +36,7 @@ namespace NadekoBot.Modules.Administration.Commands
internal override void Init(CommandGroupBuilder cgb)
{
cgb.CreateCommand(Module.Prefix + "voicenotif")
.Description("Enables notifications on who joined/left the voice channel.\n**Usage**:.voicenotif Karaoke club")
.Description("Enables notifications on who joined/left the voice channel. |.voicenotif Karaoke club")
.Parameter("voice_name", ParameterType.Unparsed)
.Do(DoFunc());
}

View File

@ -56,7 +56,7 @@ namespace NadekoBot.Modules.Administration.Commands
sendMessages: PermValue.Deny)).ConfigureAwait(false);
}
var afterVch = e.After.VoiceChannel;
if (afterVch != null)
if (afterVch != null && e.Server.AFKChannel != afterVch)
{
var textChannel = e.Server.FindChannels(
GetChannelName(afterVch.Name),

View File

@ -7,6 +7,10 @@ using System.Threading.Tasks;
namespace NadekoBot.Classes.ClashOfClans
{
public enum DestroyStars
{
One, Two, Three
}
internal class Caller
{
public string CallUser { get; }
@ -15,6 +19,9 @@ namespace NadekoBot.Classes.ClashOfClans
public bool BaseDestroyed { get; internal set; }
public int Stars { get; set; } = 3;
public Caller(string callUser, DateTime timeAdded, bool baseDestroyed)
{
CallUser = callUser;
@ -148,7 +155,7 @@ namespace NadekoBot.Classes.ClashOfClans
{
if (bases[i].BaseDestroyed)
{
sb.AppendLine($"`{i + 1}.` ✅ `{bases[i].CallUser}` ⭐ ⭐ ⭐");
sb.AppendLine($"`{i + 1}.` ✅ `{bases[i].CallUser}` {new string('⭐', bases[i].Stars)}");
}
else
{
@ -161,13 +168,14 @@ namespace NadekoBot.Classes.ClashOfClans
return sb.ToString();
}
internal int FinishClaim(string user)
internal int FinishClaim(string user, int stars = 3)
{
user = user.Trim();
for (var i = 0; i < bases.Length; i++)
{
if (bases[i]?.BaseDestroyed != false || bases[i]?.CallUser != user) continue;
bases[i].BaseDestroyed = true;
bases[i].Stars = stars;
return i;
}
throw new InvalidOperationException($"@{user} You are either not participating in that war, or you already destroyed a base.");

View File

@ -5,6 +5,8 @@ using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using NadekoBot.Modules.Permissions.Classes;
namespace NadekoBot.Modules.ClashOfClans
{
@ -21,10 +23,12 @@ namespace NadekoBot.Modules.ClashOfClans
manager.CreateCommands("", cgb =>
{
cgb.AddCheck(PermissionChecker.Instance);
cgb.CreateCommand(Prefix + "createwar")
.Alias(Prefix + "cw")
.Description(
$"Creates a new war by specifying a size (>10 and multiple of 5) and enemy clan name.\n**Usage**:{Prefix}cw 15 The Enemy Clan")
$"Creates a new war by specifying a size (>10 and multiple of 5) and enemy clan name. |{Prefix}cw 15 The Enemy Clan")
.Parameter("size")
.Parameter("enemy_clan", ParameterType.Unparsed)
.Do(async e =>
@ -102,7 +106,7 @@ namespace NadekoBot.Modules.ClashOfClans
cgb.CreateCommand(Prefix + "listwar")
.Alias(Prefix + "lw")
.Description($"Shows the active war claims by a number. Shows all wars in a short way if no number is specified.\n**Usage**: {Prefix}lw [war_number] or {Prefix}lw")
.Description($"Shows the active war claims by a number. Shows all wars in a short way if no number is specified. | {Prefix}lw [war_number] or {Prefix}lw")
.Parameter("number", ParameterType.Optional)
.Do(async e =>
{
@ -143,7 +147,7 @@ namespace NadekoBot.Modules.ClashOfClans
cgb.CreateCommand(Prefix + "claim")
.Alias(Prefix + "call")
.Alias(Prefix + "c")
.Description($"Claims a certain base from a certain war. You can supply a name in the third optional argument to claim in someone else's place. \n**Usage**: {Prefix}call [war_number] [base_number] [optional_other_name]")
.Description($"Claims a certain base from a certain war. You can supply a name in the third optional argument to claim in someone else's place. | {Prefix}call [war_number] [base_number] [optional_other_name]")
.Parameter("number")
.Parameter("baseNumber")
.Parameter("other_name", ParameterType.Unparsed)
@ -179,38 +183,31 @@ namespace NadekoBot.Modules.ClashOfClans
cgb.CreateCommand(Prefix + "claimfinish")
.Alias(Prefix + "cf")
.Description($"Finish your claim if you destroyed a base. Optional second argument finishes for someone else.\n**Usage**: {Prefix}cf [war_number] [optional_other_name]")
.Alias(Prefix + "cf3")
.Alias(Prefix + "claimfinish3")
.Description($"Finish your claim with 3 stars if you destroyed a base. Optional second argument finishes for someone else. | {Prefix}cf [war_number] [optional_other_name]")
.Parameter("number", ParameterType.Required)
.Parameter("other_name", ParameterType.Unparsed)
.Do(async e =>
{
var warInfo = GetInfo(e);
if (warInfo == null || warInfo.Item1.Count == 0)
{
await e.Channel.SendMessage("💢🔰 **That war does not exist.**").ConfigureAwait(false);
return;
}
var usr =
string.IsNullOrWhiteSpace(e.GetArg("other_name")) ?
e.User.Name :
e.GetArg("other_name");
.Do(e => FinishClaim(e));
var war = warInfo.Item1[warInfo.Item2];
try
{
var baseNum = war.FinishClaim(usr);
await e.Channel.SendMessage($"❗🔰{e.User.Mention} **DESTROYED** a base #{baseNum + 1} in a war against {war.ShortPrint()}").ConfigureAwait(false);
}
catch (Exception ex)
{
await e.Channel.SendMessage($"💢🔰 {ex.Message}").ConfigureAwait(false);
}
});
cgb.CreateCommand(Prefix + "claimfinish2")
.Alias(Prefix + "cf2")
.Description($"Finish your claim with 2 stars if you destroyed a base. Optional second argument finishes for someone else. | {Prefix}cf [war_number] [optional_other_name]")
.Parameter("number", ParameterType.Required)
.Parameter("other_name", ParameterType.Unparsed)
.Do(e => FinishClaim(e, 2));
cgb.CreateCommand(Prefix + "claimfinish1")
.Alias(Prefix + "cf1")
.Description($"Finish your claim with 1 stars if you destroyed a base. Optional second argument finishes for someone else. | {Prefix}cf [war_number] [optional_other_name]")
.Parameter("number", ParameterType.Required)
.Parameter("other_name", ParameterType.Unparsed)
.Do(e => FinishClaim(e, 1));
cgb.CreateCommand(Prefix + "unclaim")
.Alias(Prefix + "uncall")
.Alias(Prefix + "uc")
.Description($"Removes your claim from a certain war. Optional second argument denotes a person in whos place to unclaim\n**Usage**: {Prefix}uc [war_number] [optional_other_name]")
.Description($"Removes your claim from a certain war. Optional second argument denotes a person in whos place to unclaim | {Prefix}uc [war_number] [optional_other_name]")
.Parameter("number", ParameterType.Required)
.Parameter("other_name", ParameterType.Unparsed)
.Do(async e =>
@ -239,7 +236,7 @@ namespace NadekoBot.Modules.ClashOfClans
cgb.CreateCommand(Prefix + "endwar")
.Alias(Prefix + "ew")
.Description($"Ends the war with a given index.\n**Usage**:{Prefix}ew [war_number]")
.Description($"Ends the war with a given index. |{Prefix}ew [war_number]")
.Parameter("number")
.Do(async e =>
{
@ -257,6 +254,31 @@ namespace NadekoBot.Modules.ClashOfClans
});
}
private async Task FinishClaim(CommandEventArgs e, int stars = 3)
{
var warInfo = GetInfo(e);
if (warInfo == null || warInfo.Item1.Count == 0)
{
await e.Channel.SendMessage("💢🔰 **That war does not exist.**").ConfigureAwait(false);
return;
}
var usr =
string.IsNullOrWhiteSpace(e.GetArg("other_name")) ?
e.User.Name :
e.GetArg("other_name");
var war = warInfo.Item1[warInfo.Item2];
try
{
var baseNum = war.FinishClaim(usr, stars);
await e.Channel.SendMessage($"❗🔰{e.User.Mention} **DESTROYED** a base #{baseNum + 1} in a war against {war.ShortPrint()}").ConfigureAwait(false);
}
catch (Exception ex)
{
await e.Channel.SendMessage($"💢🔰 {ex.Message}").ConfigureAwait(false);
}
}
private static Tuple<List<ClashWar>, int> GetInfo(CommandEventArgs e)
{
//check if there are any wars

View File

@ -23,7 +23,7 @@ namespace NadekoBot.Modules.Conversations.Commands
internal override void Init(CommandGroupBuilder cgb)
{
cgb.CreateCommand("rip")
.Description("Shows a grave image of someone with a start year\n**Usage**: @NadekoBot rip @Someone 2000")
.Description("Shows a grave image of someone with a start year | @NadekoBot rip @Someone 2000")
.Parameter("user", ParameterType.Required)
.Parameter("year", ParameterType.Optional)
.Do(async e =>

View File

@ -32,7 +32,7 @@ namespace NadekoBot.Modules.Conversations
cgb.AddCheck(PermissionChecker.Instance);
cgb.CreateCommand("..")
.Description("Adds a new quote with the specified name (single word) and message (no limit).\n**Usage**: .. abc My message")
.Description("Adds a new quote with the specified name (single word) and message (no limit). | .. abc My message")
.Parameter("keyword", ParameterType.Required)
.Parameter("text", ParameterType.Unparsed)
.Do(async e =>
@ -53,7 +53,7 @@ namespace NadekoBot.Modules.Conversations
});
cgb.CreateCommand("...")
.Description("Shows a random quote with a specified name.\n**Usage**: .. abc")
.Description("Shows a random quote with a specified name. | .. abc")
.Parameter("keyword", ParameterType.Required)
.Do(async e =>
{
@ -73,7 +73,7 @@ namespace NadekoBot.Modules.Conversations
cgb.CreateCommand("..qdel")
.Alias("..quotedelete")
.Description("Deletes all quotes with the specified keyword. You have to either be bot owner or the creator of the quote to delete it.\n**Usage**: `..qdel abc`")
.Description("Deletes all quotes with the specified keyword. You have to either be bot owner or the creator of the quote to delete it. | `..qdel abc`")
.Parameter("quote", ParameterType.Required)
.Do(async e =>
{
@ -100,15 +100,6 @@ namespace NadekoBot.Modules.Conversations
commands.ForEach(cmd => cmd.Init(cgb));
cgb.CreateCommand("uptime")
.Description("Shows how long Nadeko has been running for.")
.Do(async e =>
{
var time = (DateTime.Now - Process.GetCurrentProcess().StartTime);
var str = string.Format("I have been running for {0} days, {1} hours, and {2} minutes.", time.Days, time.Hours, time.Minutes);
await e.Channel.SendMessage(str).ConfigureAwait(false);
});
cgb.CreateCommand("die")
.Description("Works only for the owner. Shuts the bot down.")
.Do(async e =>
@ -158,7 +149,7 @@ namespace NadekoBot.Modules.Conversations
});
cgb.CreateCommand("fire")
.Description("Shows a unicode fire message. Optional parameter [x] tells her how many times to repeat the fire.\n**Usage**: @NadekoBot fire [x]")
.Description("Shows a unicode fire message. Optional parameter [x] tells her how many times to repeat the fire. | @NadekoBot fire [x]")
.Parameter("times", ParameterType.Optional)
.Do(async e =>
{
@ -180,38 +171,6 @@ namespace NadekoBot.Modules.Conversations
await e.Channel.SendMessage(str).ConfigureAwait(false);
});
cgb.CreateCommand("slm")
.Description("Shows the message where you were last mentioned in this channel (checks last 10k messages)")
.Do(async e =>
{
Message msg = null;
var msgs = (await e.Channel.DownloadMessages(100).ConfigureAwait(false))
.Where(m => m.MentionedUsers.Contains(e.User))
.OrderByDescending(m => m.Timestamp);
if (msgs.Any())
msg = msgs.First();
else
{
var attempt = 0;
Message lastMessage = null;
while (msg == null && attempt++ < 5)
{
var msgsarr = await e.Channel.DownloadMessages(100, lastMessage?.Id).ConfigureAwait(false);
msg = msgsarr
.Where(m => m.MentionedUsers.Contains(e.User))
.OrderByDescending(m => m.Timestamp)
.FirstOrDefault();
lastMessage = msgsarr.OrderBy(m => m.Timestamp).First();
}
}
if (msg != null)
await e.Channel.SendMessage($"Last message mentioning you was at {msg.Timestamp}\n**Message from {msg.User.Name}:** {msg.RawText}")
.ConfigureAwait(false);
else
await e.Channel.SendMessage("I can't find a message mentioning you.").ConfigureAwait(false);
});
cgb.CreateCommand("dump")
.Description("Dumps all of the invites it can to dump.txt.** Owner Only.**")
.Do(async e =>

View File

@ -50,7 +50,7 @@ namespace NadekoBot.Modules.CustomReactions
var c = cgb.CreateCommand(commandName);
if (commandName.Contains(NadekoBot.BotMention))
c.Alias(commandName.Replace("<@", "<@!"));
c.Description($"Custom reaction.\n**Usage**:{command.Key}")
c.Description($"Custom reaction. |{command.Key}")
.Parameter("args", ParameterType.Unparsed)
.Do(async e =>
{

View File

@ -7,7 +7,7 @@ namespace NadekoBot.Classes
/// Base DiscordCommand Class.
/// Inherit this class to create your own command.
/// </summary>
internal abstract class DiscordCommand
public abstract class DiscordCommand
{
/// <summary>

View File

@ -3,7 +3,7 @@ using System.Collections.Generic;
using NadekoBot.Classes;
namespace NadekoBot.Modules {
internal abstract class DiscordModule : IModule {
public abstract class DiscordModule : IModule {
protected readonly HashSet<DiscordCommand> commands = new HashSet<DiscordCommand>();
public abstract string Prefix { get; }

View File

@ -21,11 +21,18 @@ namespace NadekoBot.Modules.Gambling
{
cgb.CreateCommand(Module.Prefix + "roll")
.Description("Rolls 0-100. If you supply a number [x] it rolls up to 30 normal dice." +
" If you split 2 numbers with letter d (xdy) it will roll x dice from 1 to y.\n**Usage**: $roll or $roll 7 or $roll 3d5")
" If you split 2 numbers with letter d (xdy) it will roll x dice from 1 to y. | $roll or $roll 7 or $roll 3d5")
.Parameter("num", ParameterType.Optional)
.Do(RollFunc());
cgb.CreateCommand(Module.Prefix + "rolluo")
.Description("Rolls 0-100. If you supply a number [x] it rolls up to 30 normal dice (unordered)." +
" If you split 2 numbers with letter d (xdy) it will roll x dice from 1 to y. | $roll or $roll 7 or $roll 3d5")
.Parameter("num", ParameterType.Optional)
.Do(RollFunc(false));
cgb.CreateCommand(Module.Prefix + "nroll")
.Description("Rolls in a given range.\n**Usage**: `$nroll 5` (rolls 0-5) or `$nroll 5-15`")
.Description("Rolls in a given range. | `$nroll 5` (rolls 0-5) or `$nroll 5-15`")
.Parameter("range", ParameterType.Required)
.Do(NRollFunc());
}
@ -40,7 +47,7 @@ namespace NadekoBot.Modules.Gambling
Regex dndRegex = new Regex(@"(?<n1>\d+)d(?<n2>\d+)", RegexOptions.Compiled);
private Func<CommandEventArgs, Task> RollFunc()
private Func<CommandEventArgs, Task> RollFunc(bool ordered = true)
{
var r = new Random();
return async e =>
@ -73,7 +80,7 @@ namespace NadekoBot.Modules.Gambling
arr[i] = r.Next(1, n2 + 1);
}
var elemCnt = 0;
await e.Channel.SendMessage($"`Rolled {n1} {(n1 == 1 ? "die" : "dice")} 1-{n2}.`\n`Result:` " + string.Join(", ", arr.OrderBy(x => x).Select(x => elemCnt++ % 2 == 0 ? $"**{x}**" : x.ToString()))).ConfigureAwait(false);
await e.Channel.SendMessage($"`Rolled {n1} {(n1 == 1 ? "die" : "dice")} 1-{n2}.`\n`Result:` " + string.Join(", ", (ordered ? arr.OrderBy(x => x).AsEnumerable() : arr).Select(x => elemCnt++ % 2 == 0 ? $"**{x}**" : x.ToString()))).ConfigureAwait(false);
}
return;
}
@ -92,6 +99,8 @@ namespace NadekoBot.Modules.Gambling
{
var randomNumber = r.Next(1, 7);
var toInsert = dices.Count;
if (ordered)
{
if (randomNumber == 6 || dices.Count == 0)
toInsert = 0;
else if (randomNumber != 1)
@ -103,6 +112,10 @@ namespace NadekoBot.Modules.Gambling
break;
}
}
}
else {
toInsert = dices.Count;
}
dices.Insert(toInsert, GetDice(randomNumber));
values.Insert(toInsert, randomNumber);
}

View File

@ -17,7 +17,7 @@ namespace NadekoBot.Modules.Gambling
internal override void Init(CommandGroupBuilder cgb)
{
cgb.CreateCommand(Module.Prefix + "draw")
.Description("Draws a card from the deck.If you supply number [x], she draws up to 5 cards from the deck.\n**Usage**: $draw [x]")
.Description("Draws a card from the deck.If you supply number [x], she draws up to 5 cards from the deck. | $draw [x]")
.Parameter("count", ParameterType.Optional)
.Do(DrawCardFunc());

View File

@ -15,14 +15,68 @@ namespace NadekoBot.Modules.Gambling
internal override void Init(CommandGroupBuilder cgb)
{
cgb.CreateCommand(Module.Prefix + "flip")
.Description("Flips coin(s) - heads or tails, and shows an image.\n**Usage**: `$flip` or `$flip 3`")
.Description("Flips coin(s) - heads or tails, and shows an image. | `$flip` or `$flip 3`")
.Parameter("count", ParameterType.Optional)
.Do(FlipCoinFunc());
cgb.CreateCommand(Module.Prefix + "betflip")
.Alias(Prefix+"bf")
.Description($"Bet to guess will the result be heads or tails. Guessing award you double flowers you've bet. | `{Prefix}bf 5 heads` or `{Prefix}bf 3 t`")
.Parameter("amount", ParameterType.Required)
.Parameter("guess", ParameterType.Required)
.Do(BetFlipCoinFunc());
}
private readonly Random rng = new Random();
public Func<CommandEventArgs, Task> BetFlipCoinFunc() => async e =>
{
var amountstr = e.GetArg("amount").Trim();
var guessStr = e.GetArg("guess").Trim().ToUpperInvariant();
if (guessStr != "H" && guessStr != "T" && guessStr != "HEADS" && guessStr != "TAILS")
return;
int amount;
if (!int.TryParse(amountstr, out amount) || amount < 1)
return;
var userFlowers = GamblingModule.GetUserFlowers(e.User.Id);
if (userFlowers < amount)
{
await e.Channel.SendMessage($"{e.User.Mention} You don't have enough {NadekoBot.Config.CurrencyName}s. You only have {userFlowers}{NadekoBot.Config.CurrencySign}.").ConfigureAwait(false);
return;
}
await FlowersHandler.RemoveFlowers(e.User, "Betflip Gamble", (int)amount, true).ConfigureAwait(false);
//heads = true
//tails = false
var guess = guessStr == "HEADS" || guessStr == "H";
bool result = false;
if (rng.Next(0, 2) == 1) {
await e.Channel.SendFile("heads.png", Properties.Resources.heads.ToStream(System.Drawing.Imaging.ImageFormat.Png)).ConfigureAwait(false);
result = true;
}
else {
await e.Channel.SendFile("tails.png", Properties.Resources.tails.ToStream(System.Drawing.Imaging.ImageFormat.Png)).ConfigureAwait(false);
}
string str;
if (guess == result)
{
str = $"{e.User.Mention}`You guessed it!` You won {amount * 2}{NadekoBot.Config.CurrencySign}";
await FlowersHandler.AddFlowersAsync(e.User, "Betflip Gamble", amount * 2, true).ConfigureAwait(false);
}
else
str = $"{e.User.Mention}`More luck next time.`";
await e.Channel.SendMessage(str).ConfigureAwait(false);
};
public Func<CommandEventArgs, Task> FlipCoinFunc() => async e =>
{

View File

@ -13,7 +13,6 @@ namespace NadekoBot.Modules.Gambling
{
internal class GamblingModule : DiscordModule
{
public GamblingModule()
{
commands.Add(new DrawCommand(this));
@ -50,7 +49,7 @@ namespace NadekoBot.Modules.Gambling
});
cgb.CreateCommand(Prefix + "$$")
.Description(string.Format("Check how much {0}s a person has. (Defaults to yourself)\n**Usage**:`{1}$$` or `{1}$$ @Someone`",
.Description(string.Format("Check how much {0}s a person has. (Defaults to yourself) |`{1}$$` or `{1}$$ @Someone`",
NadekoBot.Config.CurrencyName, Prefix))
.Parameter("all", ParameterType.Unparsed)
.Do(async e =>
@ -82,11 +81,11 @@ namespace NadekoBot.Modules.Gambling
if (userFlowers < amount)
{
await e.Channel.SendMessage($"{e.User.Mention} You don't have enough {NadekoBot.Config.CurrencyName}s. You have only {userFlowers}{NadekoBot.Config.CurrencySign}.").ConfigureAwait(false);
await e.Channel.SendMessage($"{e.User.Mention} You don't have enough {NadekoBot.Config.CurrencyName}s. You only have {userFlowers}{NadekoBot.Config.CurrencySign}.").ConfigureAwait(false);
return;
}
FlowersHandler.RemoveFlowers(e.User, "Gift", (int)amount);
await FlowersHandler.RemoveFlowers(e.User, "Gift", (int)amount, true).ConfigureAwait(false);
await FlowersHandler.AddFlowersAsync(mentionedUser, "Gift", (int)amount).ConfigureAwait(false);
await e.Channel.SendMessage($"{e.User.Mention} successfully sent {amount} {NadekoBot.Config.CurrencyName}s to {mentionedUser.Mention}!").ConfigureAwait(false);
@ -94,7 +93,7 @@ namespace NadekoBot.Modules.Gambling
});
cgb.CreateCommand(Prefix + "award")
.Description("Gives someone a certain amount of flowers. **Bot Owner Only!**\n**Usage**: `$award 100 @person`")
.Description("Gives someone a certain amount of flowers. **Bot Owner Only!** | `$award 100 @person`")
.AddCheck(SimpleCheckers.OwnerOnly())
.Parameter("amount", ParameterType.Required)
.Parameter("receiver", ParameterType.Unparsed)
@ -132,11 +131,58 @@ namespace NadekoBot.Modules.Gambling
if (mentionedUser == null)
return;
FlowersHandler.RemoveFlowers(mentionedUser, $"Taken by bot owner.({e.User.Name}/{e.User.Id})", (int)amount);
await FlowersHandler.RemoveFlowers(mentionedUser, $"Taken by bot owner.({e.User.Name}/{e.User.Id})", (int)amount).ConfigureAwait(false);
await e.Channel.SendMessage($"{e.User.Mention} successfully took {amount} {NadekoBot.Config.CurrencyName}s from {mentionedUser.Mention}!").ConfigureAwait(false);
});
cgb.CreateCommand(Prefix + "betroll")
.Alias(Prefix + "br")
.Description($"Bets a certain amount of {NadekoBot.Config.CurrencyName}s and rolls a dice. Rolling over 66 yields x2 flowers, over 90 - x3 and 100 x10. | {Prefix}br 5")
.Parameter("amount",ParameterType.Required)
.Do(async e =>
{
var amountstr = e.GetArg("amount").Trim();
int amount;
if (!int.TryParse(amountstr, out amount) || amount < 1)
return;
var userFlowers = GetUserFlowers(e.User.Id);
if (userFlowers < amount)
{
await e.Channel.SendMessage($"{e.User.Mention} You don't have enough {NadekoBot.Config.CurrencyName}s. You only have {userFlowers}{NadekoBot.Config.CurrencySign}.").ConfigureAwait(false);
return;
}
await FlowersHandler.RemoveFlowers(e.User, "Betroll Gamble", (int)amount, true).ConfigureAwait(false);
var rng = new Random().Next(0, 101);
var str = $"{e.User.Mention} `You rolled {rng}.` ";
if (rng < 67)
{
str += "Better luck next time.";
}
else if (rng < 90)
{
str += $"Congratulations! You won {amount * 2}{NadekoBot.Config.CurrencySign} for rolling above 66";
await FlowersHandler.AddFlowersAsync(e.User, "Betroll Gamble", amount * 2, true).ConfigureAwait(false);
}
else if (rng < 100)
{
str += $"Congratulations! You won {amount * 3}{NadekoBot.Config.CurrencySign} for rolling above 90.";
await FlowersHandler.AddFlowersAsync(e.User, "Betroll Gamble", amount * 3, true).ConfigureAwait(false);
}
else {
str += $"👑 Congratulations! You won {amount * 10}{NadekoBot.Config.CurrencySign} for rolling **100**. 👑";
await FlowersHandler.AddFlowersAsync(e.User, "Betroll Gamble", amount * 10, true).ConfigureAwait(false);
}
await e.Channel.SendMessage(str).ConfigureAwait(false);
});
cgb.CreateCommand(Prefix + "leaderboard")
.Alias(Prefix + "lb")
.Do(async e =>
@ -148,18 +194,18 @@ namespace NadekoBot.Modules.Gambling
await e.Channel.SendMessage(
richest.Aggregate(new StringBuilder(
$@"```xl
Id $$$
"),
(cur, cs) => cur.AppendLine(
$@"┣━━━━━━━━━━━━━━━━━━━╋━━━━━━━┫
{cs.UserId,-18} {cs.Value,5} ")
).ToString() + "┗━━━━━━━━━━━━━━━━━━━┻━━━━━━━┛```");
$@"┣━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━┫
{(e.Server.Users.Where(u => u.Id == (ulong)cs.UserId).FirstOrDefault()?.Name.TrimTo(18, true) ?? cs.UserId.ToString()),-20} {cs.Value,5} ")
).ToString() + "┗━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━┛```").ConfigureAwait(false);
});
});
}
private static long GetUserFlowers(ulong userId) =>
public static long GetUserFlowers(ulong userId) =>
Classes.DbHandler.Instance.GetStateByUserId((long)userId)?.Value ?? 0;
}
}

View File

@ -297,7 +297,7 @@ namespace NadekoBot.Modules.Games.Commands
internal override void Init(CommandGroupBuilder cgb)
{
cgb.CreateCommand(Module.Prefix + "leet")
.Description($"Converts a text to leetspeak with 6 (1-6) severity levels\n**Usage**: {Module.Prefix}leet 3 Hello")
.Description($"Converts a text to leetspeak with 6 (1-6) severity levels | {Module.Prefix}leet 3 Hello")
.Parameter("level", ParameterType.Required)
.Parameter("text", ParameterType.Unparsed)
.Do(async e =>

View File

@ -28,23 +28,35 @@ namespace NadekoBot.Modules.Games.Commands
rng = new Random();
}
private static readonly ConcurrentDictionary<ulong, DateTime> plantpickCooldowns = new ConcurrentDictionary<ulong, DateTime>();
private async void PotentialFlowerGeneration(object sender, Discord.MessageEventArgs e)
{
if (e.Server == null || e.Channel.IsPrivate)
try
{
if (e.Server == null || e.Channel.IsPrivate || e.Message.IsAuthor)
return;
var config = Classes.SpecificConfigurations.Default.Of(e.Server.Id);
if (config.GenerateCurrencyChannels.Contains(e.Channel.Id))
var now = DateTime.Now;
int cd;
DateTime lastSpawned;
if (config.GenerateCurrencyChannels.TryGetValue(e.Channel.Id, out cd))
if (!plantpickCooldowns.TryGetValue(e.Channel.Id, out lastSpawned) || (lastSpawned + new TimeSpan(0, cd, 0)) < now)
{
var rnd = Math.Abs(GetRandomNumber());
if ((rnd % 50) == 0)
{
var msg = await e.Channel.SendFile(GetRandomCurrencyImagePath());
await e.Channel.SendMessage($"❗ A random {NadekoBot.Config.CurrencyName} appeared! Pick it up by typing `>pick`");
var msg2 = await e.Channel.SendMessage($"❗ A random {NadekoBot.Config.CurrencyName} appeared! Pick it up by typing `>pick`");
plantedFlowerChannels.AddOrUpdate(e.Channel.Id, msg, (u, m) => { m.Delete().GetAwaiter().GetResult(); return msg; });
plantpickCooldowns.AddOrUpdate(e.Channel.Id, now, (i, d) => now);
await Task.Delay(5000);
await msg2.Delete();
}
}
}
catch { }
}
//channelid/messageid pair
ConcurrentDictionary<ulong, Message> plantedFlowerChannels = new ConcurrentDictionary<ulong, Message>();
@ -80,7 +92,7 @@ namespace NadekoBot.Modules.Games.Commands
e.Channel.SendMessage($"There is already a {NadekoBot.Config.CurrencyName} in this channel.");
return;
}
var removed = FlowersHandler.RemoveFlowers(e.User, "Planted a flower.", 1);
var removed = FlowersHandler.RemoveFlowers(e.User, "Planted a flower.", 1).GetAwaiter().GetResult();
if (!removed)
{
e.Channel.SendMessage($"You don't have any {NadekoBot.Config.CurrencyName}s.").Wait();
@ -104,19 +116,27 @@ namespace NadekoBot.Modules.Games.Commands
cgb.CreateCommand(Prefix + "gencurrency")
.Alias(Prefix + "gc")
.Description($"Toggles currency generation on this channel. Every posted message will have 2% chance to spawn a {NadekoBot.Config.CurrencyName}. Requires Manage Messages permission. | `>gc`")
.Description($"Toggles currency generation on this channel. Every posted message will have 2% chance to spawn a {NadekoBot.Config.CurrencyName}. Optional parameter cooldown time in minutes, 5 minutes by default. Requires Manage Messages permission. | `>gc` or `>gc 60`")
.AddCheck(SimpleCheckers.ManageMessages())
.Parameter("cd", ParameterType.Unparsed)
.Do(async e =>
{
var cdStr = e.GetArg("cd");
int cd = 2;
if (!int.TryParse(cdStr, out cd) || cd < 0)
{
cd = 2;
}
var config = SpecificConfigurations.Default.Of(e.Server.Id);
if (config.GenerateCurrencyChannels.Remove(e.Channel.Id))
int throwaway;
if (config.GenerateCurrencyChannels.TryRemove(e.Channel.Id, out throwaway))
{
await e.Channel.SendMessage("`Currency generation disabled on this channel.`");
}
else
{
config.GenerateCurrencyChannels.Add(e.Channel.Id);
await e.Channel.SendMessage("`Currency generation enabled on this channel.`");
if (config.GenerateCurrencyChannels.TryAdd(e.Channel.Id, cd))
await e.Channel.SendMessage($"`Currency generation enabled on this channel. Cooldown is {cd} minutes.`");
}
});
}

View File

@ -23,7 +23,7 @@ namespace NadekoBot.Modules.Games.Commands
internal override void Init(CommandGroupBuilder cgb)
{
cgb.CreateCommand(Module.Prefix + "poll")
.Description("Creates a poll, only person who has manage server permission can do it.\n**Usage**: >poll Question?;Answer1;Answ 2;A_3")
.Description("Creates a poll, only person who has manage server permission can do it. | >poll Question?;Answer1;Answ 2;A_3")
.Parameter("allargs", ParameterType.Unparsed)
.Do(async e =>
{

View File

@ -20,7 +20,7 @@ namespace NadekoBot.Modules.Games.Commands
cgb.CreateCommand(Module.Prefix + "t")
.Description($"Starts a game of trivia. You can add nohint to prevent hints." +
"First player to get to 10 points wins by default. You can specify a different number. 30 seconds per question." +
$"\n**Usage**:`{Module.Prefix}t nohint` or `{Module.Prefix}t 5 nohint`")
$" |`{Module.Prefix}t nohint` or `{Module.Prefix}t 5 nohint`")
.Parameter("args", ParameterType.Multiple)
.Do(async e =>
{

View File

@ -36,7 +36,7 @@ namespace NadekoBot.Modules.Games
commands.ForEach(cmd => cmd.Init(cgb));
cgb.CreateCommand(Prefix + "choose")
.Description("Chooses a thing from a list of things\n**Usage**: >choose Get up;Sleep;Sleep more")
.Description("Chooses a thing from a list of things | >choose Get up;Sleep;Sleep more")
.Parameter("list", ParameterType.Unparsed)
.Do(async e =>
{
@ -67,7 +67,7 @@ namespace NadekoBot.Modules.Games
});
cgb.CreateCommand(Prefix + "rps")
.Description("Play a game of rocket paperclip scissors with Nadeko.\n**Usage**: >rps scissors")
.Description("Play a game of rocket paperclip scissors with Nadeko. | >rps scissors")
.Parameter("input", ParameterType.Required)
.Do(async e =>
{
@ -107,7 +107,7 @@ namespace NadekoBot.Modules.Games
});
cgb.CreateCommand(Prefix + "linux")
.Description($"Prints a customizable Linux interjection\n**Usage**: `{Prefix}linux Spyware Windows`")
.Description($"Prints a customizable Linux interjection | `{Prefix}linux Spyware Windows`")
.Parameter("gnu", ParameterType.Required)
.Parameter("linux", ParameterType.Required)
.Do(async e =>

View File

@ -25,7 +25,7 @@ namespace NadekoBot.Classes.Help.Commands
.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.Aliases.FirstOrDefault() + "" ?? "")}`__**\n**Desc:** {com.Description.Replace("|", "\n**Usage:**")}").ConfigureAwait(false);
}).ConfigureAwait(false);
};
public static string HelpString {
@ -62,7 +62,7 @@ Version: `{NadekoStats.Instance.BotVersion}`";
helpstr += PrintCommandHelp(com);
}
helpstr = helpstr.Replace(NadekoBot.BotMention, "@BotName");
helpstr = helpstr.Replace("\n**Usage**:", " | ").Replace("**Usage**:", " | ").Replace("**Description:**", " | ").Replace("\n|", " | \n");
helpstr = helpstr.Replace(" |", " | ").Replace("**Usage**:", " | ").Replace("**Description:**", " | ").Replace("\n|", " | \n");
#if DEBUG
File.WriteAllText("../../../commandlist.md", helpstr);
#else
@ -74,7 +74,7 @@ Version: `{NadekoStats.Instance.BotVersion}`";
{
cgb.CreateCommand(Module.Prefix + "h")
.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' ")
.Description("Either shows a help for a single command, or PMs you help link if no arguments are specified. | '-h !m q' or just '-h' ")
.Parameter("command", ParameterType.Unparsed)
.Do(HelpFunc());
cgb.CreateCommand(Module.Prefix + "hgit")

View File

@ -53,13 +53,16 @@ namespace NadekoBot.Modules.Help
await e.Channel.SendMessage("That module does not exist.").ConfigureAwait(false);
return;
}
var i = 0;
if (module != "customreactions" && module != "conversations")
{
await e.Channel.SendMessage("`List Of Commands:`\n" + SearchHelper.ShowInPrettyCode<Command>(cmdsArray,
el => $"{el.Text,-15}{"[" + el.Aliases.FirstOrDefault() + "]",-8}"))
.ConfigureAwait(false);
}
else
{
await e.Channel.SendMessage("`List Of Commands:`\n• " + string.Join("\n• ", cmdsArray.Select(c => $"{c.Text}")));
}
await e.Channel.SendMessage($"`You can type \"{Prefix}h command_name\" to see the help about that specific command.`").ConfigureAwait(false);
});
});

View File

@ -12,7 +12,8 @@ namespace NadekoBot.Modules.Music.Classes
{
Radio,
Normal,
Local
Local,
Soundcloud
}
public enum StreamState
@ -51,6 +52,7 @@ namespace NadekoBot.Modules.Music.Classes
public bool RepeatSong { get; private set; } = false;
public bool RepeatPlaylist { get; private set; } = false;
public bool Autoplay { get; set; } = false;
public uint MaxQueueSize { get; set; } = 0;
public MusicPlayer(Channel startingVoiceChannel, float? defaultVolume)
{
@ -168,13 +170,15 @@ namespace NadekoBot.Modules.Music.Classes
}
}
public void AddSong(Song s)
public void AddSong(Song s, string username)
{
if (s == null)
throw new ArgumentNullException(nameof(s));
ThrowIfQueueFull();
lock (playlistLock)
{
s.MusicPlayer = this;
s.QueuerName = username.TrimTo(10);
playlist.Add(s);
}
}
@ -243,5 +247,13 @@ namespace NadekoBot.Modules.Music.Classes
internal bool ToggleRepeatPlaylist() => this.RepeatPlaylist = !this.RepeatPlaylist;
internal bool ToggleAutoplay() => this.Autoplay = !this.Autoplay;
internal void ThrowIfQueueFull()
{
if (MaxQueueSize == 0)
return;
if (playlist.Count >= MaxQueueSize)
throw new PlaylistFullException();
}
}
}

View File

@ -0,0 +1,12 @@
using System;
namespace NadekoBot.Modules.Music.Classes
{
class PlaylistFullException : Exception
{
public PlaylistFullException(string message) : base(message)
{
}
public PlaylistFullException() : base("Queue is full.") { }
}
}

View File

@ -27,8 +27,9 @@ namespace NadekoBot.Modules.Music.Classes
{
public StreamState State { get; internal set; }
public string PrettyName =>
$"**【 {SongInfo.Title.TrimTo(55)} 】**`{(SongInfo.Provider ?? "-")}`";
$"**【 {SongInfo.Title.TrimTo(55)} 】**`{(SongInfo.Provider ?? "-")}` `by {QueuerName}`";
public SongInfo SongInfo { get; }
public string QueuerName { get; set; }
private PoopyBuffer songBuffer { get; } = new PoopyBuffer(NadekoBot.Config.BufferSize);
@ -244,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.");

View File

@ -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<SoundCloudVideo> GetVideoAsync(string url)
public async Task<SoundCloudVideo> 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<SoundCloudVideo> 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<SoundCloudVideo[]>(response).Where(s => s.Streamable).FirstOrDefault();
if (responseObj?.Kind != "track")
throw new InvalidOperationException("Query yielded no results.");
return responseObj;
}
}
public class SoundCloudVideo

View File

@ -41,7 +41,7 @@ namespace NadekoBot.Modules.Music
cgb.CreateCommand("next")
.Alias("n")
.Alias("skip")
.Description("Goes to the next song in the queue. You have to be in the same voice channel as the bot.\n**Usage**: `!m n`")
.Description("Goes to the next song in the queue. You have to be in the same voice channel as the bot. | `!m n`")
.Do(e =>
{
MusicPlayer musicPlayer;
@ -52,7 +52,7 @@ namespace NadekoBot.Modules.Music
cgb.CreateCommand("stop")
.Alias("s")
.Description("Stops the music and clears the playlist. Stays in the channel.\n**Usage**: `!m s`")
.Description("Stops the music and clears the playlist. Stays in the channel. | `!m s`")
.Do(e =>
{
MusicPlayer musicPlayer;
@ -67,7 +67,7 @@ namespace NadekoBot.Modules.Music
cgb.CreateCommand("destroy")
.Alias("d")
.Description("Completely stops the music and unbinds the bot from the channel. " +
"(may cause weird behaviour)\n**Usage**: `!m d`")
"(may cause weird behaviour) | `!m d`")
.Do(e =>
{
MusicPlayer musicPlayer;
@ -78,7 +78,7 @@ namespace NadekoBot.Modules.Music
cgb.CreateCommand("pause")
.Alias("p")
.Description("Pauses or Unpauses the song.\n**Usage**: `!m p`")
.Description("Pauses or Unpauses the song. | `!m p`")
.Do(async e =>
{
MusicPlayer musicPlayer;
@ -96,11 +96,11 @@ namespace NadekoBot.Modules.Music
.Alias("q")
.Alias("yq")
.Description("Queue a song using keywords or a link. Bot will join your voice channel." +
"**You must be in a voice channel**.\n**Usage**: `!m q Dream Of Venice`")
"**You must be in a voice channel**. | `!m q Dream Of Venice`")
.Parameter("query", ParameterType.Unparsed)
.Do(async e =>
{
await QueueSong(e.Channel, e.User.VoiceChannel, e.GetArg("query")).ConfigureAwait(false);
await QueueSong(e.User, e.Channel, e.User.VoiceChannel, e.GetArg("query")).ConfigureAwait(false);
if (e.Server.CurrentUser.GetPermissions(e.Channel).ManageMessages)
{
await Task.Delay(10000).ConfigureAwait(false);
@ -108,24 +108,24 @@ 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**. | `!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")
.Description("Lists 15 currently queued songs per page. Default page is 1.\n**Usage**: `!m lq` or `!m lq 2`")
.Description("Lists 15 currently queued songs per page. Default page is 1. | `!m lq` or `!m lq 2`")
.Parameter("page", ParameterType.Optional)
.Do(async e =>
{
@ -163,7 +163,7 @@ namespace NadekoBot.Modules.Music
cgb.CreateCommand("nowplaying")
.Alias("np")
.Description("Shows the song currently playing.\n**Usage**: `!m np`")
.Description("Shows the song currently playing. | `!m np`")
.Do(async e =>
{
MusicPlayer musicPlayer;
@ -178,7 +178,7 @@ namespace NadekoBot.Modules.Music
cgb.CreateCommand("volume")
.Alias("vol")
.Description("Sets the music volume 0-100%\n**Usage**: `!m vol 50`")
.Description("Sets the music volume 0-100% | `!m vol 50`")
.Parameter("val", ParameterType.Required)
.Do(async e =>
{
@ -201,7 +201,7 @@ namespace NadekoBot.Modules.Music
cgb.CreateCommand("defvol")
.Alias("dv")
.Description("Sets the default music volume when music playback is started (0-100)." +
" Persists through restarts.\n**Usage**: `!m dv 80`")
" Persists through restarts. | `!m dv 80`")
.Parameter("val", ParameterType.Required)
.Do(async e =>
{
@ -217,8 +217,9 @@ namespace NadekoBot.Modules.Music
await e.Channel.SendMessage($"🎵 `Default volume set to {volume}%`").ConfigureAwait(false);
});
cgb.CreateCommand("mute").Alias("min")
.Description("Sets the music volume to 0%\n**Usage**: `!m min`")
cgb.CreateCommand("mute")
.Alias("min")
.Description("Sets the music volume to 0% | `!m min`")
.Do(e =>
{
MusicPlayer musicPlayer;
@ -230,7 +231,7 @@ namespace NadekoBot.Modules.Music
});
cgb.CreateCommand("max")
.Description("Sets the music volume to 100% (real max is actually 150%).\n**Usage**: `!m max`")
.Description("Sets the music volume to 100%. | `!m max`")
.Do(e =>
{
MusicPlayer musicPlayer;
@ -242,7 +243,7 @@ namespace NadekoBot.Modules.Music
});
cgb.CreateCommand("half")
.Description("Sets the music volume to 50%.\n**Usage**: `!m half`")
.Description("Sets the music volume to 50%. | `!m half`")
.Do(e =>
{
MusicPlayer musicPlayer;
@ -255,7 +256,7 @@ namespace NadekoBot.Modules.Music
cgb.CreateCommand("shuffle")
.Alias("sh")
.Description("Shuffles the current playlist.\n**Usage**: `!m sh`")
.Description("Shuffles the current playlist. | `!m sh`")
.Do(async e =>
{
MusicPlayer musicPlayer;
@ -275,7 +276,7 @@ namespace NadekoBot.Modules.Music
cgb.CreateCommand("playlist")
.Alias("pl")
.Description("Queues up to 50 songs from a youtube playlist specified by a link, or keywords.\n**Usage**: `!m pl playlist link or name`")
.Description("Queues up to 500 songs from a youtube playlist specified by a link, or keywords. | `!m pl playlist link or name`")
.Parameter("playlist", ParameterType.Unparsed)
.Do(async e =>
{
@ -296,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
@ -308,8 +309,10 @@ namespace NadekoBot.Modules.Music
{
try
{
await QueueSong(e.Channel, e.User.VoiceChannel, id, true).ConfigureAwait(false);
await QueueSong(e.User, e.Channel, e.User.VoiceChannel, id, true).ConfigureAwait(false);
}
catch (PlaylistFullException)
{ break; }
catch { }
}
await msg.Edit("🎵 `Playlist queue complete.`").ConfigureAwait(false);
@ -326,14 +329,16 @@ 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<SoundCloudVideo[]>();
await QueueSong(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<SoundCloudVideo[]>();
await QueueSong(e.User, e.Channel, e.User.VoiceChannel, scvids[0].TrackLink).ConfigureAwait(false);
MusicPlayer mp;
if (!MusicPlayers.TryGetValue(e.Server, out mp))
return;
foreach (var svideo in scvids.Skip(1))
{
try
{
mp.AddSong(new Song(new Classes.SongInfo
{
@ -342,13 +347,15 @@ namespace NadekoBot.Modules.Music
Uri = svideo.StreamLink,
ProviderType = MusicType.Normal,
Query = svideo.TrackLink,
}));
}), e.User.Name);
}
catch (PlaylistFullException) { break; }
}
});
cgb.CreateCommand("localplaylst")
.Alias("lopl")
.Description("Queues all songs from a directory. **Bot Owner Only!**\n**Usage**: `!m lopl C:/music/classical`")
.Description("Queues all songs from a directory. **Bot Owner Only!** | `!m lopl C:/music/classical`")
.Parameter("directory", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.OwnerOnly())
.Do(async e =>
@ -362,7 +369,15 @@ namespace NadekoBot.Modules.Music
.Where(x => !x.Attributes.HasFlag(FileAttributes.Hidden | FileAttributes.System));
foreach (var file in fileEnum)
{
await QueueSong(e.Channel, e.User.VoiceChannel, file.FullName, true, MusicType.Local).ConfigureAwait(false);
try
{
await QueueSong(e.User, e.Channel, e.User.VoiceChannel, file.FullName, true, MusicType.Local).ConfigureAwait(false);
}
catch (PlaylistFullException)
{
break;
}
catch { }
}
await e.Channel.SendMessage("🎵 `Directory queue complete.`").ConfigureAwait(false);
}
@ -370,7 +385,7 @@ namespace NadekoBot.Modules.Music
});
cgb.CreateCommand("radio").Alias("ra")
.Description("Queues a radio stream from a link. It can be a direct mp3 radio stream, .m3u, .pls .asx or .xspf\n**Usage**: `!m ra radio link here`")
.Description("Queues a radio stream from a link. It can be a direct mp3 radio stream, .m3u, .pls .asx or .xspf (Usage Video: <https://streamable.com/al54>) | `!m ra radio link here`")
.Parameter("radio_link", ParameterType.Required)
.Do(async e =>
{
@ -379,7 +394,7 @@ namespace NadekoBot.Modules.Music
await e.Channel.SendMessage("💢 You need to be in a voice channel on this server.\n If you are already in a voice channel, try rejoining it.").ConfigureAwait(false);
return;
}
await QueueSong(e.Channel, e.User.VoiceChannel, e.GetArg("radio_link"), musicType: MusicType.Radio).ConfigureAwait(false);
await QueueSong(e.User, e.Channel, e.User.VoiceChannel, e.GetArg("radio_link"), musicType: MusicType.Radio).ConfigureAwait(false);
if (e.Server.CurrentUser.GetPermissions(e.Channel).ManageMessages)
{
await Task.Delay(10000).ConfigureAwait(false);
@ -389,7 +404,7 @@ namespace NadekoBot.Modules.Music
cgb.CreateCommand("local")
.Alias("lo")
.Description("Queues a local file by specifying a full path. **Bot Owner Only!**\n**Usage**: `!m lo C:/music/mysong.mp3`")
.Description("Queues a local file by specifying a full path. **Bot Owner Only!** | `!m lo C:/music/mysong.mp3`")
.Parameter("path", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.OwnerOnly())
.Do(async e =>
@ -397,12 +412,12 @@ namespace NadekoBot.Modules.Music
var arg = e.GetArg("path");
if (string.IsNullOrWhiteSpace(arg))
return;
await QueueSong(e.Channel, e.User.VoiceChannel, e.GetArg("path"), musicType: MusicType.Local).ConfigureAwait(false);
await QueueSong(e.User, e.Channel, e.User.VoiceChannel, e.GetArg("path"), musicType: MusicType.Local).ConfigureAwait(false);
});
cgb.CreateCommand("move")
.Alias("mv")
.Description("Moves the bot to your voice channel. (works only if music is already playing)\n**Usage**: `!m mv`")
.Description("Moves the bot to your voice channel. (works only if music is already playing) | `!m mv`")
.Do(e =>
{
MusicPlayer musicPlayer;
@ -414,7 +429,7 @@ namespace NadekoBot.Modules.Music
cgb.CreateCommand("remove")
.Alias("rm")
.Description("Remove a song by its # in the queue, or 'all' to remove whole queue.\n**Usage**: `!m rm 5`")
.Description("Remove a song by its # in the queue, or 'all' to remove whole queue. | `!m rm 5`")
.Parameter("num", ParameterType.Required)
.Do(async e =>
{
@ -447,7 +462,7 @@ namespace NadekoBot.Modules.Music
//var msRegex = new Regex(@"(?<n1>\d+)>(?<n2>\d+)", RegexOptions.Compiled);
cgb.CreateCommand("movesong")
.Alias("ms")
.Description($"Moves a song from one position to another.\n**Usage**: `{Prefix} ms` 5>3")
.Description($"Moves a song from one position to another. | `{Prefix} ms` 5>3")
.Parameter("fromto")
.Do(async e =>
{
@ -468,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;
}
@ -477,12 +492,35 @@ 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);
});
cgb.CreateCommand("setmaxqueue")
.Alias("smq")
.Description($"Sets a maximum queue size. Supply 0 or no argument to have no limit. | `{Prefix} smq` 50 or `{Prefix} smq`")
.Parameter("size", ParameterType.Unparsed)
.Do(async e =>
{
MusicPlayer musicPlayer;
if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer))
{
return;
}
var sizeStr = e.GetArg("size")?.Trim();
uint size = 0;
if (string.IsNullOrWhiteSpace(sizeStr) || !uint.TryParse(sizeStr, out size))
{
size = 0;
}
musicPlayer.MaxQueueSize = size;
await e.Channel.SendMessage($"🎵 `Max queue set to {(size == 0 ? ("unlimited") : size + " tracks")}`");
});
cgb.CreateCommand("cleanup")
.Description("Cleans up hanging voice connections. **Bot Owner Only!**\n**Usage**: `!m cleanup`")
.Description("Cleans up hanging voice connections. **Bot Owner Only!** | `!m cleanup`")
.AddCheck(SimpleCheckers.OwnerOnly())
.Do(e =>
{
@ -501,7 +539,7 @@ namespace NadekoBot.Modules.Music
cgb.CreateCommand("reptcursong")
.Alias("rcs")
.Description("Toggles repeat of current song.\n**Usage**: `!m rcs`")
.Description("Toggles repeat of current song. | `!m rcs`")
.Do(async e =>
{
MusicPlayer musicPlayer;
@ -519,7 +557,7 @@ namespace NadekoBot.Modules.Music
cgb.CreateCommand("rpeatplaylst")
.Alias("rpl")
.Description("Toggles repeat of all songs in the queue (every song that finishes is added to the end of the queue).\n**Usage**: `!m rpl`")
.Description("Toggles repeat of all songs in the queue (every song that finishes is added to the end of the queue). | `!m rpl`")
.Do(async e =>
{
MusicPlayer musicPlayer;
@ -530,7 +568,7 @@ namespace NadekoBot.Modules.Music
});
cgb.CreateCommand("save")
.Description("Saves a playlist under a certain name. Name must be no longer than 20 characters and mustn't contain dashes.\n**Usage**: `!m save classical1`")
.Description("Saves a playlist under a certain name. Name must be no longer than 20 characters and mustn't contain dashes. | `!m save classical1`")
.Parameter("name", ParameterType.Unparsed)
.Do(async e =>
{
@ -583,7 +621,7 @@ namespace NadekoBot.Modules.Music
});
cgb.CreateCommand("load")
.Description("Loads a playlist under a certain name. \n**Usage**: `!m load classical-1`")
.Description("Loads a playlist under a certain name. | `!m load classical-1`")
.Parameter("name", ParameterType.Unparsed)
.Do(async e =>
{
@ -628,7 +666,11 @@ namespace NadekoBot.Modules.Music
{
try
{
await QueueSong(textCh, voiceCh, si.Query, true, (MusicType)si.ProviderType).ConfigureAwait(false);
await QueueSong(e.User, textCh, voiceCh, si.Query, true, (MusicType)si.ProviderType).ConfigureAwait(false);
}
catch (PlaylistFullException)
{
break;
}
catch (Exception ex)
{
@ -639,7 +681,7 @@ 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`")
.Description("Lists all playlists. Paginated. 20 per page. Default page is 0. |`!m pls 1`")
.Parameter("num", ParameterType.Optional)
.Do(e =>
{
@ -649,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")
@ -668,7 +710,7 @@ namespace NadekoBot.Modules.Music
DbHandler.Instance.Delete<MusicPlaylist>(plnum);
else
DbHandler.Instance.DeleteWhere<MusicPlaylist>(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")
@ -719,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")
@ -733,14 +775,14 @@ 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);
});
});
}
public static async Task QueueSong(Channel textCh, Channel voiceCh, string query, bool silent = false, MusicType musicType = MusicType.Normal)
public static async Task QueueSong(User queuer, Channel textCh, Channel voiceCh, string query, bool silent = false, MusicType musicType = MusicType.Normal)
{
if (voiceCh == null || voiceCh.Server != textCh.Server)
{
@ -772,7 +814,7 @@ namespace NadekoBot.Modules.Music
lastFinishedMessage = await textCh.SendMessage($"🎵`Finished`{song.PrettyName}").ConfigureAwait(false);
if (mp.Autoplay && mp.Playlist.Count == 0 && song.SongInfo.Provider == "YouTube")
{
await QueueSong(textCh, voiceCh, await SearchHelper.GetRelatedVideoId(song.SongInfo.Query), silent, musicType).ConfigureAwait(false);
await QueueSong(queuer, textCh, voiceCh, await SearchHelper.GetRelatedVideoId(song.SongInfo.Query), silent, musicType).ConfigureAwait(false);
}
}
catch (Exception e)
@ -800,8 +842,19 @@ namespace NadekoBot.Modules.Music
};
return mp;
});
var resolvedSong = await Song.ResolveSong(query, musicType).ConfigureAwait(false);
musicPlayer.AddSong(resolvedSong);
Song resolvedSong;
try
{
musicPlayer.ThrowIfQueueFull();
resolvedSong = await Song.ResolveSong(query, musicType).ConfigureAwait(false);
musicPlayer.AddSong(resolvedSong, queuer.Name);
}
catch (PlaylistFullException)
{
await textCh.SendMessage($"🎵 `Queue is full at {musicPlayer.MaxQueueSize}/{musicPlayer.MaxQueueSize}.` ");
throw;
}
if (!silent)
{
var queuedMessage = await textCh.SendMessage($"🎵`Queued`{resolvedSong.PrettyName} **at** `#{musicPlayer.Playlist.Count}`").ConfigureAwait(false);

View File

@ -22,7 +22,7 @@ namespace NadekoBot.Modules.NSFW
cgb.AddCheck(PermissionChecker.Instance);
cgb.CreateCommand(Prefix + "hentai")
.Description("Shows a random NSFW hentai image from gelbooru and danbooru with a given tag. Tag is optional but preffered. (multiple tags are appended with +)\n**Usage**: ~hentai yuri+kissing")
.Description("Shows a random NSFW hentai image from gelbooru and danbooru with a given tag. Tag is optional but preffered. (multiple tags are appended with +) | ~hentai yuri+kissing")
.Parameter("tag", ParameterType.Unparsed)
.Do(async e =>
{
@ -39,7 +39,7 @@ namespace NadekoBot.Modules.NSFW
await e.Channel.SendMessage("`No results.`");
});
cgb.CreateCommand(Prefix + "danbooru")
.Description("Shows a random hentai image from danbooru with a given tag. Tag is optional but preffered. (multiple tags are appended with +)\n**Usage**: ~danbooru yuri+kissing")
.Description("Shows a random hentai image from danbooru with a given tag. Tag is optional but preffered. (multiple tags are appended with +) | ~danbooru yuri+kissing")
.Parameter("tag", ParameterType.Unparsed)
.Do(async e =>
{
@ -51,7 +51,7 @@ namespace NadekoBot.Modules.NSFW
await e.Channel.SendMessage(link).ConfigureAwait(false);
});
cgb.CreateCommand(Prefix + "gelbooru")
.Description("Shows a random hentai image from gelbooru with a given tag. Tag is optional but preffered. (multiple tags are appended with +)\n**Usage**: ~gelbooru yuri+kissing")
.Description("Shows a random hentai image from gelbooru with a given tag. Tag is optional but preffered. (multiple tags are appended with +) | ~gelbooru yuri+kissing")
.Parameter("tag", ParameterType.Unparsed)
.Do(async e =>
{
@ -64,7 +64,7 @@ namespace NadekoBot.Modules.NSFW
});
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**: ~rule34 yuri+kissing")
.Description("Shows a random image from rule34.xx with a given tag. Tag is optional but preffered. (multiple tags are appended with +) | ~rule34 yuri+kissing")
.Parameter("tag", ParameterType.Unparsed)
.Do(async e =>
{
@ -76,7 +76,7 @@ namespace NadekoBot.Modules.NSFW
await e.Channel.SendMessage(link).ConfigureAwait(false);
});
cgb.CreateCommand(Prefix + "e621")
.Description("Shows a random hentai image from e621.net with a given tag. Tag is optional but preffered. Use spaces for multiple tags.\n**Usage**: ~e621 yuri kissing")
.Description("Shows a random hentai image from e621.net with a given tag. Tag is optional but preffered. Use spaces for multiple tags. | ~e621 yuri kissing")
.Parameter("tag", ParameterType.Unparsed)
.Do(async e =>
{

View File

@ -4,6 +4,7 @@ using Discord.Commands.Permissions;
using NadekoBot.Classes.JSONModels;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace NadekoBot.Modules.Permissions.Classes
@ -13,7 +14,7 @@ namespace NadekoBot.Modules.Permissions.Classes
{
public static PermissionChecker Instance { get; } = new PermissionChecker();
private ConcurrentDictionary<User, DateTime> timeBlackList { get; } = new ConcurrentDictionary<User, DateTime>();
private HashSet<ulong> timeBlackList { get; } = new HashSet<ulong>();
static PermissionChecker() { }
private PermissionChecker()
@ -46,10 +47,10 @@ namespace NadekoBot.Modules.Permissions.Classes
return false;
}
if (timeBlackList.ContainsKey(user))
if (timeBlackList.Contains(user.Id))
return false;
timeBlackList.TryAdd(user, DateTime.Now);
timeBlackList.Add(user.Id);
if (!channel.IsPrivate && !channel.Server.CurrentUser.GetPermissions(channel).SendMessages)
{

View File

@ -55,7 +55,7 @@ namespace NadekoBot.Modules.Permissions.Commands
.Alias(Module.Prefix + "cfi")
.Description("Enables or disables automatic deleting of invites on the channel." +
"If no channel supplied, it will default to current one. Use ALL to apply to all existing channels at once." +
"\n**Usage**: ;cfi enable #general-chat")
" | ;cfi enable #general-chat")
.Parameter("bool")
.Parameter("channel", ParameterType.Optional)
.Do(async e =>
@ -95,7 +95,7 @@ namespace NadekoBot.Modules.Permissions.Commands
cgb.CreateCommand(Module.Prefix + "srvrfilterinv")
.Alias(Module.Prefix + "sfi")
.Description("Enables or disables automatic deleting of invites on the server.\n**Usage**: ;sfi disable")
.Description("Enables or disables automatic deleting of invites on the server. | ;sfi disable")
.Parameter("bool")
.Do(async e =>
{

View File

@ -53,7 +53,7 @@ namespace NadekoBot.Modules.Permissions.Commands
.Alias(Module.Prefix + "cfw")
.Description("Enables or disables automatic deleting of messages containing banned words on the channel." +
"If no channel supplied, it will default to current one. Use ALL to apply to all existing channels at once." +
"\n**Usage**: ;cfw enable #general-chat")
" | ;cfw enable #general-chat")
.Parameter("bool")
.Parameter("channel", ParameterType.Optional)
.Do(async e =>
@ -89,7 +89,7 @@ namespace NadekoBot.Modules.Permissions.Commands
cgb.CreateCommand(Module.Prefix + "addfilterword")
.Alias(Module.Prefix + "afw")
.Description("Adds a new word to the list of filtered words" +
"\n**Usage**: ;afw poop")
" | ;afw poop")
.Parameter("word", ParameterType.Unparsed)
.Do(async e =>
{
@ -111,7 +111,7 @@ namespace NadekoBot.Modules.Permissions.Commands
cgb.CreateCommand(Module.Prefix + "rmvfilterword")
.Alias(Module.Prefix + "rfw")
.Description("Removes the word from the list of filtered words" +
"\n**Usage**: ;rw poop")
" | ;rw poop")
.Parameter("word", ParameterType.Unparsed)
.Do(async e =>
{
@ -133,7 +133,7 @@ namespace NadekoBot.Modules.Permissions.Commands
cgb.CreateCommand(Module.Prefix + "lstfilterwords")
.Alias(Module.Prefix + "lfw")
.Description("Shows a list of filtered words" +
"\n**Usage**: ;lfw")
" | ;lfw")
.Do(async e =>
{
try
@ -152,7 +152,7 @@ namespace NadekoBot.Modules.Permissions.Commands
cgb.CreateCommand(Module.Prefix + "srvrfilterwords")
.Alias(Module.Prefix + "sfw")
.Description("Enables or disables automatic deleting of messages containing forbidden words on the server.\n**Usage**: ;sfw disable")
.Description("Enables or disables automatic deleting of messages containing forbidden words on the server. | ;sfw disable")
.Parameter("bool")
.Do(async e =>
{

View File

@ -60,7 +60,7 @@ namespace NadekoBot.Modules.Permissions
cgb.CreateCommand(Prefix + "rolepermscopy")
.Alias(Prefix + "rpc")
.Description($"Copies BOT PERMISSIONS (not discord permissions) from one role to another.\n**Usage**:`{Prefix}rpc Some Role ~ Some other role`")
.Description($"Copies BOT PERMISSIONS (not discord permissions) from one role to another. |`{Prefix}rpc Some Role ~ Some other role`")
.Parameter("from_to", ParameterType.Unparsed)
.Do(async e =>
{
@ -88,7 +88,7 @@ namespace NadekoBot.Modules.Permissions
});
cgb.CreateCommand(Prefix + "chnlpermscopy")
.Alias(Prefix + "cpc")
.Description($"Copies BOT PERMISSIONS (not discord permissions) from one channel to another.\n**Usage**:`{Prefix}cpc Some Channel ~ Some other channel`")
.Description($"Copies BOT PERMISSIONS (not discord permissions) from one channel to another. |`{Prefix}cpc Some Channel ~ Some other channel`")
.Parameter("from_to", ParameterType.Unparsed)
.Do(async e =>
{
@ -116,7 +116,7 @@ namespace NadekoBot.Modules.Permissions
});
cgb.CreateCommand(Prefix + "usrpermscopy")
.Alias(Prefix + "upc")
.Description($"Copies BOT PERMISSIONS (not discord permissions) from one role to another.\n**Usage**:`{Prefix}upc @SomeUser ~ @SomeOtherUser`")
.Description($"Copies BOT PERMISSIONS (not discord permissions) from one role to another. |`{Prefix}upc @SomeUser ~ @SomeOtherUser`")
.Parameter("from_to", ParameterType.Unparsed)
.Do(async e =>
{
@ -145,7 +145,7 @@ namespace NadekoBot.Modules.Permissions
cgb.CreateCommand(Prefix + "verbose")
.Alias(Prefix + "v")
.Description("Sets whether to show when a command/module is blocked.\n**Usage**: ;verbose true")
.Description("Sets whether to show when a command/module is blocked. | ;verbose true")
.Parameter("arg", ParameterType.Required)
.Do(async e =>
{
@ -168,7 +168,7 @@ namespace NadekoBot.Modules.Permissions
cgb.CreateCommand(Prefix + "roleperms")
.Alias(Prefix + "rp")
.Description("Shows banned permissions for a certain role. No argument means for everyone.\n**Usage**: ;rp AwesomeRole")
.Description("Shows banned permissions for a certain role. No argument means for everyone. | ;rp AwesomeRole")
.Parameter("role", ParameterType.Unparsed)
.Do(async e =>
{
@ -194,7 +194,7 @@ namespace NadekoBot.Modules.Permissions
cgb.CreateCommand(Prefix + "chnlperms")
.Alias(Prefix + "cp")
.Description("Shows banned permissions for a certain channel. No argument means for this channel.\n**Usage**: ;cp #dev")
.Description("Shows banned permissions for a certain channel. No argument means for this channel. | ;cp #dev")
.Parameter("channel", ParameterType.Unparsed)
.Do(async e =>
{
@ -219,7 +219,7 @@ namespace NadekoBot.Modules.Permissions
cgb.CreateCommand(Prefix + "userperms")
.Alias(Prefix + "up")
.Description("Shows banned permissions for a certain user. No argument means for yourself.\n**Usage**: ;up Kwoth")
.Description("Shows banned permissions for a certain user. No argument means for yourself. | ;up Kwoth")
.Parameter("user", ParameterType.Unparsed)
.Do(async e =>
{
@ -245,7 +245,7 @@ namespace NadekoBot.Modules.Permissions
.Alias(Prefix + "sm")
.Parameter("module", ParameterType.Required)
.Parameter("bool", ParameterType.Required)
.Description("Sets a module's permission at the server level.\n**Usage**: ;sm [module_name] enable")
.Description("Sets a module's permission at the server level. | ;sm \"module name\" enable")
.Do(async e =>
{
try
@ -269,7 +269,7 @@ namespace NadekoBot.Modules.Permissions
cgb.CreateCommand(Prefix + "srvrcmd").Alias(Prefix + "sc")
.Parameter("command", ParameterType.Required)
.Parameter("bool", ParameterType.Required)
.Description("Sets a command's permission at the server level.\n**Usage**: ;sc [command_name] disable")
.Description("Sets a command's permission at the server level. | ;sc \"command name\" disable")
.Do(async e =>
{
try
@ -294,7 +294,7 @@ namespace NadekoBot.Modules.Permissions
.Parameter("module", ParameterType.Required)
.Parameter("bool", ParameterType.Required)
.Parameter("role", ParameterType.Unparsed)
.Description("Sets a module's permission at the role level.\n**Usage**: ;rm [module_name] enable [role_name]")
.Description("Sets a module's permission at the role level. | ;rm \"module name\" enable MyRole")
.Do(async e =>
{
try
@ -332,7 +332,7 @@ namespace NadekoBot.Modules.Permissions
.Parameter("command", ParameterType.Required)
.Parameter("bool", ParameterType.Required)
.Parameter("role", ParameterType.Unparsed)
.Description("Sets a command's permission at the role level.\n**Usage**: ;rc [command_name] disable [role_name]")
.Description("Sets a command's permission at the role level. | ;rc \"command name\" disable MyRole")
.Do(async e =>
{
try
@ -370,7 +370,7 @@ namespace NadekoBot.Modules.Permissions
.Parameter("module", ParameterType.Required)
.Parameter("bool", ParameterType.Required)
.Parameter("channel", ParameterType.Unparsed)
.Description("Sets a module's permission at the channel level.\n**Usage**: ;cm [module_name] enable [channel_name]")
.Description("Sets a module's permission at the channel level. | ;cm \"module name\" enable SomeChannel")
.Do(async e =>
{
try
@ -413,7 +413,7 @@ namespace NadekoBot.Modules.Permissions
.Parameter("command", ParameterType.Required)
.Parameter("bool", ParameterType.Required)
.Parameter("channel", ParameterType.Unparsed)
.Description("Sets a command's permission at the channel level.\n**Usage**: ;cc [command_name] enable [channel_name]")
.Description("Sets a command's permission at the channel level. | ;cc \"command name\" enable SomeChannel")
.Do(async e =>
{
try
@ -451,7 +451,7 @@ namespace NadekoBot.Modules.Permissions
.Parameter("module", ParameterType.Required)
.Parameter("bool", ParameterType.Required)
.Parameter("user", ParameterType.Unparsed)
.Description("Sets a module's permission at the user level.\n**Usage**: ;um [module_name] enable [user_name]")
.Description("Sets a module's permission at the user level. | ;um \"module name\" enable SomeUsername")
.Do(async e =>
{
try
@ -477,7 +477,7 @@ namespace NadekoBot.Modules.Permissions
.Parameter("command", ParameterType.Required)
.Parameter("bool", ParameterType.Required)
.Parameter("user", ParameterType.Unparsed)
.Description("Sets a command's permission at the user level.\n**Usage**: ;uc [command_name] enable [user_name]")
.Description("Sets a command's permission at the user level. | ;uc \"command name\" enable SomeUsername")
.Do(async e =>
{
try
@ -501,7 +501,7 @@ namespace NadekoBot.Modules.Permissions
cgb.CreateCommand(Prefix + "allsrvrmdls").Alias(Prefix + "asm")
.Parameter("bool", ParameterType.Required)
.Description("Sets permissions for all modules at the server level.\n**Usage**: ;asm [enable/disable]")
.Description("Sets permissions for all modules at the server level. | ;asm [enable/disable]")
.Do(async e =>
{
try
@ -527,7 +527,7 @@ namespace NadekoBot.Modules.Permissions
cgb.CreateCommand(Prefix + "allsrvrcmds").Alias(Prefix + "asc")
.Parameter("module", ParameterType.Required)
.Parameter("bool", ParameterType.Required)
.Description("Sets permissions for all commands from a certain module at the server level.\n**Usage**: ;asc [module_name] [enable/disable]")
.Description("Sets permissions for all commands from a certain module at the server level. | ;asc \"module name\" [enable/disable]")
.Do(async e =>
{
try
@ -554,7 +554,7 @@ namespace NadekoBot.Modules.Permissions
cgb.CreateCommand(Prefix + "allchnlmdls").Alias(Prefix + "acm")
.Parameter("bool", ParameterType.Required)
.Parameter("channel", ParameterType.Unparsed)
.Description("Sets permissions for all modules at the channel level.\n**Usage**: ;acm [enable/disable] [channel_name]")
.Description("Sets permissions for all modules at the channel level. | ;acm [enable/disable] SomeChannel")
.Do(async e =>
{
try
@ -583,7 +583,7 @@ namespace NadekoBot.Modules.Permissions
.Parameter("module", ParameterType.Required)
.Parameter("bool", ParameterType.Required)
.Parameter("channel", ParameterType.Unparsed)
.Description("Sets permissions for all commands from a certain module at the channel level.\n**Usage**: ;acc [module_name] [enable/disable] [channel_name]")
.Description("Sets permissions for all commands from a certain module at the channel level. | ;acc \"module name\" [enable/disable] SomeChannel")
.Do(async e =>
{
try
@ -610,7 +610,7 @@ namespace NadekoBot.Modules.Permissions
cgb.CreateCommand(Prefix + "allrolemdls").Alias(Prefix + "arm")
.Parameter("bool", ParameterType.Required)
.Parameter("role", ParameterType.Unparsed)
.Description("Sets permissions for all modules at the role level.\n**Usage**: ;arm [enable/disable] [role_name]")
.Description("Sets permissions for all modules at the role level. | ;arm [enable/disable] MyRole")
.Do(async e =>
{
try
@ -638,7 +638,7 @@ namespace NadekoBot.Modules.Permissions
.Parameter("module", ParameterType.Required)
.Parameter("bool", ParameterType.Required)
.Parameter("role", ParameterType.Unparsed)
.Description("Sets permissions for all commands from a certain module at the role level.\n**Usage**: ;arc [module_name] [enable/disable] [role_name]")
.Description("Sets permissions for all commands from a certain module at the role level. | ;arc \"module name\" [enable/disable] MyRole")
.Do(async e =>
{
try
@ -678,7 +678,7 @@ namespace NadekoBot.Modules.Permissions
});
cgb.CreateCommand(Prefix + "ubl")
.Description("Blacklists a mentioned user.\n**Usage**: ;ubl [user_mention]")
.Description("Blacklists a mentioned user. | ;ubl [user_mention]")
.Parameter("user", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.OwnerOnly())
.Do(async e =>
@ -694,7 +694,7 @@ namespace NadekoBot.Modules.Permissions
});
cgb.CreateCommand(Prefix + "uubl")
.Description($"Unblacklists a mentioned user.\n**Usage**: {Prefix}uubl [user_mention]")
.Description($"Unblacklists a mentioned user. | {Prefix}uubl [user_mention]")
.Parameter("user", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.OwnerOnly())
.Do(async e =>
@ -717,7 +717,7 @@ namespace NadekoBot.Modules.Permissions
});
cgb.CreateCommand(Prefix + "cbl")
.Description("Blacklists a mentioned channel (#general for example).\n**Usage**: ;cbl [channel_mention]")
.Description("Blacklists a mentioned channel (#general for example). | ;cbl #some_channel")
.Parameter("channel", ParameterType.Unparsed)
.Do(async e =>
{
@ -732,7 +732,7 @@ namespace NadekoBot.Modules.Permissions
});
cgb.CreateCommand(Prefix + "cubl")
.Description("Unblacklists a mentioned channel (#general for example).\n**Usage**: ;cubl [channel_mention]")
.Description("Unblacklists a mentioned channel (#general for example). | ;cubl #some_channel")
.Parameter("channel", ParameterType.Unparsed)
.Do(async e =>
{
@ -747,7 +747,7 @@ namespace NadekoBot.Modules.Permissions
});
cgb.CreateCommand(Prefix + "sbl")
.Description("Blacklists a server by a name or id (#general for example). **BOT OWNER ONLY**\n**Usage**: ;sbl [servername/serverid]")
.Description("Blacklists a server by a name or id (#general for example). **BOT OWNER ONLY** | ;sbl [servername/serverid]")
.Parameter("server", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.OwnerOnly())
.Do(async e =>

View File

@ -80,7 +80,7 @@ namespace NadekoBot.Modules.Pokemon
commands.ForEach(cmd => cmd.Init(cgb));
cgb.CreateCommand(Prefix + "attack")
.Description("Attacks a target with the given move")
.Description($"Attacks a target with the given move. Use `{Prefix}movelist` to see a list of moves your type can use. | `{Prefix}attack \"vine whip\" @someguy`")
.Parameter("move", ParameterType.Required)
.Parameter("target", ParameterType.Unparsed)
.Do(async e =>
@ -210,7 +210,7 @@ namespace NadekoBot.Modules.Pokemon
});
cgb.CreateCommand(Prefix + "heal")
.Description($"Heals someone. Revives those that fainted. Costs a {NadekoBot.Config.CurrencyName} \n**Usage**:{Prefix}revive @someone")
.Description($"Heals someone. Revives those who fainted. Costs a {NadekoBot.Config.CurrencyName} | {Prefix}heal @someone")
.Parameter("target", ParameterType.Unparsed)
.Do(async e =>
{
@ -242,7 +242,7 @@ namespace NadekoBot.Modules.Pokemon
return;
}
var target = (usr.Id == e.User.Id) ? "yourself" : usr.Name;
FlowersHandler.RemoveFlowers(e.User, $"Poke-Heal {target}", amount);
await FlowersHandler.RemoveFlowers(e.User, $"Poke-Heal {target}", amount).ConfigureAwait(false);
//healing
targetStats.Hp = targetStats.MaxHp;
if (HP < 0)
@ -263,7 +263,7 @@ namespace NadekoBot.Modules.Pokemon
});
cgb.CreateCommand(Prefix + "type")
.Description($"Get the poketype of the target.\n**Usage**: {Prefix}type @someone")
.Description($"Get the poketype of the target. | {Prefix}type @someone")
.Parameter("target", ParameterType.Unparsed)
.Do(async e =>
{
@ -282,7 +282,7 @@ namespace NadekoBot.Modules.Pokemon
});
cgb.CreateCommand(Prefix + "settype")
.Description($"Set your poketype. Costs a {NadekoBot.Config.CurrencyName}.\n**Usage**: {Prefix}settype fire")
.Description($"Set your poketype. Costs a {NadekoBot.Config.CurrencyName}. | {Prefix}settype fire")
.Parameter("targetType", ParameterType.Unparsed)
.Do(async e =>
{
@ -309,7 +309,7 @@ namespace NadekoBot.Modules.Pokemon
await e.Channel.SendMessage($"{e.User.Mention} you don't have enough {NadekoBot.Config.CurrencyName}s! \nYou still need {amount - pts} {NadekoBot.Config.CurrencySign} to be able to do this!").ConfigureAwait(false);
return;
}
FlowersHandler.RemoveFlowers(e.User, $"set usertype to {targetTypeStr}", amount);
await FlowersHandler.RemoveFlowers(e.User, $"set usertype to {targetTypeStr}", amount).ConfigureAwait(false);
//Actually changing the type here
var preTypes = DbHandler.Instance.GetAllRows<UserPokeTypes>();
Dictionary<long, int> Dict = preTypes.ToDictionary(x => x.UserId, y => y.Id.Value);

View File

@ -17,7 +17,7 @@ namespace NadekoBot.Modules.Searches.Commands
{
cgb.CreateCommand(Module.Prefix + "calculate")
.Alias(Module.Prefix + "calc")
.Description("Evaluate a mathematical expression.\n**Usage**: ~calc 1+1")
.Description("Evaluate a mathematical expression. | ~calc 1+1")
.Parameter("expression", ParameterType.Unparsed)
.Do(EvalFunc());
}
@ -49,11 +49,11 @@ namespace NadekoBot.Modules.Searches.Commands
string result = parser.Parse(expression).ToString();
return result;
}
catch (OverflowException e)
catch (OverflowException)
{
return $"Overflow error on {expression}";
}
catch (FormatException e)
catch (FormatException)
{
return $"\"{expression}\" was not formatted correctly";
}

View File

@ -75,7 +75,7 @@ namespace NadekoBot.Modules.Searches.Commands
internal override void Init(CommandGroupBuilder cgb)
{
cgb.CreateCommand(Module.Prefix + "lolchamp")
.Description("Shows League Of Legends champion statistics. If there are spaces/apostrophes or in the name - omit them. Optional second parameter is a role.\n**Usage**:~lolchamp Riven or ~lolchamp Annie sup")
.Description("Shows League Of Legends champion statistics. If there are spaces/apostrophes or in the name - omit them. Optional second parameter is a role. |~lolchamp Riven or ~lolchamp Annie sup")
.Parameter("champ", ParameterType.Required)
.Parameter("position", ParameterType.Unparsed)
.Do(async e =>

View File

@ -17,7 +17,7 @@ namespace NadekoBot.Modules.Searches.Commands
internal override void Init(CommandGroupBuilder cgb)
{
cgb.CreateCommand(Module.Prefix + "osu")
.Description("Shows osu stats for a player.\n**Usage**: `~osu Name` or `~osu Name taiko`")
.Description("Shows osu stats for a player. | `~osu Name` or `~osu Name taiko`")
.Parameter("usr", ParameterType.Required)
.Parameter("mode", ParameterType.Unparsed)
.Do(async e =>
@ -56,7 +56,7 @@ namespace NadekoBot.Modules.Searches.Commands
});
cgb.CreateCommand(Module.Prefix + "osu b")
.Description("Shows information about an osu beatmap.\n**Usage**:~osu b https://osu.ppy.sh/s/127712")
.Description("Shows information about an osu beatmap. |~osu b https://osu.ppy.sh/s/127712")
.Parameter("map", ParameterType.Unparsed)
.Do(async e =>
{
@ -88,7 +88,7 @@ namespace NadekoBot.Modules.Searches.Commands
});
cgb.CreateCommand(Module.Prefix + "osu top5")
.Description("Displays a user's top 5 plays. \n**Usage**:~osu top5 Name")
.Description("Displays a user's top 5 plays. |~osu top5 Name")
.Parameter("usr", ParameterType.Required)
.Parameter("mode", ParameterType.Unparsed)
.Do(async e =>

View File

@ -42,12 +42,12 @@ namespace NadekoBot.Modules.Searches.Commands
});
cgb.CreateCommand(Prefix + "pokemonability")
.Alias(Prefix + "pokab")
.Alias(Prefix + "pokeab")
.Description("Searches for a pokemon ability.")
.Parameter("abil", ParameterType.Unparsed)
.Do(async e =>
{
var ab = e.GetArg("abil")?.Trim().ToUpperInvariant();
var ab = e.GetArg("abil")?.Trim().ToUpperInvariant().Replace(" ", "");
if (string.IsNullOrWhiteSpace(ab))
return;
foreach (var kvp in pokemonAbilities)

View File

@ -122,7 +122,7 @@ namespace NadekoBot.Modules.Searches.Commands
cgb.CreateCommand(Module.Prefix + "hitbox")
.Alias(Module.Prefix + "hb")
.Description("Notifies this channel when a certain user starts streaming." +
"\n**Usage**: ~hitbox SomeStreamer")
" | ~hitbox SomeStreamer")
.Parameter("username", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.ManageServer())
.Do(TrackStream(StreamNotificationConfig.StreamType.Hitbox));
@ -130,7 +130,7 @@ namespace NadekoBot.Modules.Searches.Commands
cgb.CreateCommand(Module.Prefix + "twitch")
.Alias(Module.Prefix + "tw")
.Description("Notifies this channel when a certain user starts streaming." +
"\n**Usage**: ~twitch SomeStreamer")
" | ~twitch SomeStreamer")
.AddCheck(SimpleCheckers.ManageServer())
.Parameter("username", ParameterType.Unparsed)
.Do(TrackStream(StreamNotificationConfig.StreamType.Twitch));
@ -138,7 +138,7 @@ namespace NadekoBot.Modules.Searches.Commands
cgb.CreateCommand(Module.Prefix + "beam")
.Alias(Module.Prefix + "bm")
.Description("Notifies this channel when a certain user starts streaming." +
"\n**Usage**: ~beam SomeStreamer")
" | ~beam SomeStreamer")
.AddCheck(SimpleCheckers.ManageServer())
.Parameter("username", ParameterType.Unparsed)
.Do(TrackStream(StreamNotificationConfig.StreamType.Beam));
@ -146,7 +146,7 @@ namespace NadekoBot.Modules.Searches.Commands
cgb.CreateCommand(Module.Prefix + "checkhitbox")
.Alias(Module.Prefix + "chhb")
.Description("Checks if a certain user is streaming on the hitbox platform." +
"\n**Usage**: ~chhb SomeStreamer")
" | ~chhb SomeStreamer")
.Parameter("username", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.ManageServer())
.Do(async e =>
@ -175,7 +175,7 @@ namespace NadekoBot.Modules.Searches.Commands
cgb.CreateCommand(Module.Prefix + "checktwitch")
.Alias(Module.Prefix + "chtw")
.Description("Checks if a certain user is streaming on the twitch platform." +
"\n**Usage**: ~chtw SomeStreamer")
" | ~chtw SomeStreamer")
.AddCheck(SimpleCheckers.ManageServer())
.Parameter("username", ParameterType.Unparsed)
.Do(async e =>
@ -204,7 +204,7 @@ namespace NadekoBot.Modules.Searches.Commands
cgb.CreateCommand(Module.Prefix + "checkbeam")
.Alias(Module.Prefix + "chbm")
.Description("Checks if a certain user is streaming on the beam platform." +
"\n**Usage**: ~chbm SomeStreamer")
" | ~chbm SomeStreamer")
.AddCheck(SimpleCheckers.ManageServer())
.Parameter("username", ParameterType.Unparsed)
.Do(async e =>
@ -233,7 +233,7 @@ namespace NadekoBot.Modules.Searches.Commands
cgb.CreateCommand(Module.Prefix + "removestream")
.Alias(Module.Prefix + "rms")
.Description("Removes notifications of a certain streamer on this channel." +
"\n**Usage**: ~rms SomeGuy")
" | ~rms SomeGuy")
.AddCheck(SimpleCheckers.ManageServer())
.Parameter("username", ParameterType.Unparsed)
.Do(async e =>
@ -261,7 +261,7 @@ namespace NadekoBot.Modules.Searches.Commands
cgb.CreateCommand(Module.Prefix + "liststreams")
.Alias(Module.Prefix + "ls")
.Description("Lists all streams you are following on this server." +
"\n**Usage**: ~ls")
" | ~ls")
.Do(async e =>
{

View File

@ -47,7 +47,7 @@ namespace NadekoBot.Modules.Searches
commands.ForEach(cmd => cmd.Init(cgb));
cgb.CreateCommand(Prefix + "we")
.Description($"Shows weather data for a specified city and a country. BOTH ARE REQUIRED. Use country abbrevations.\n**Usage**: {Prefix}we Moscow RF")
.Description($"Shows weather data for a specified city and a country. BOTH ARE REQUIRED. Use country abbrevations. | {Prefix}we Moscow RF")
.Parameter("city", ParameterType.Required)
.Parameter("country", ParameterType.Required)
.Do(async e =>
@ -157,7 +157,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
});
cgb.CreateCommand(Prefix + "i")
.Description("Pulls the first image found using a search parameter. Use ~ir for different results.\n**Usage**: ~i cute kitten")
.Description("Pulls the first image found using a search parameter. Use ~ir for different results. | ~i cute kitten")
.Parameter("query", ParameterType.Unparsed)
.Do(async e =>
{
@ -183,7 +183,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
});
cgb.CreateCommand(Prefix + "ir")
.Description("Pulls a random image using a search parameter.\n**Usage**: ~ir cute kitten")
.Description("Pulls a random image using a search parameter. | ~ir cute kitten")
.Parameter("query", ParameterType.Unparsed)
.Do(async e =>
{
@ -220,7 +220,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
});
cgb.CreateCommand(Prefix + "hs")
.Description("Searches for a Hearthstone card and shows its image. Takes a while to complete.\n**Usage**:~hs Ysera")
.Description("Searches for a Hearthstone card and shows its image. Takes a while to complete. |~hs Ysera")
.Parameter("name", ParameterType.Unparsed)
.Do(async e =>
{
@ -261,7 +261,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
});
cgb.CreateCommand(Prefix + "ud")
.Description("Searches Urban Dictionary for a word.\n**Usage**:~ud Pineapple")
.Description("Searches Urban Dictionary for a word. |~ud Pineapple")
.Parameter("query", ParameterType.Unparsed)
.Do(async e =>
{
@ -290,7 +290,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
});
// thanks to Blaubeerwald
cgb.CreateCommand(Prefix + "#")
.Description("Searches Tagdef.com for a hashtag.\n**Usage**:~# ff")
.Description("Searches Tagdef.com for a hashtag. |~# ff")
.Parameter("query", ParameterType.Unparsed)
.Do(async e =>
{
@ -404,7 +404,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
});
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")
.Description("Shows a random image from safebooru with a given tag. Tag is optional but preffered. (multiple tags are appended with +) | ~safebooru yuri+kissing")
.Parameter("tag", ParameterType.Unparsed)
.Do(async e =>
{
@ -431,7 +431,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
});
cgb.CreateCommand(Prefix + "clr")
.Description("Shows you what color corresponds to that hex.\n**Usage**: `~clr 00ff00`")
.Description("Shows you what color corresponds to that hex. | `~clr 00ff00`")
.Parameter("color", ParameterType.Unparsed)
.Do(async e =>
{
@ -480,7 +480,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
cgb.CreateCommand(Prefix + "av")
.Alias(Prefix + "avatar")
.Parameter("mention", ParameterType.Required)
.Description("Shows a mentioned person's avatar.\n**Usage**: ~av @X")
.Description("Shows a mentioned person's avatar. | ~av @X")
.Do(async e =>
{
var usr = e.Channel.FindUsers(e.GetArg("mention")).FirstOrDefault();

View File

@ -14,7 +14,7 @@ namespace NadekoBot.Modules.Translator
{
cgb.CreateCommand(Module.Prefix + "translate")
.Alias(Module.Prefix + "trans")
.Description($"Translates from>to text. From the given language to the destiation language.\n**Usage**: {Module.Prefix}trans en>fr Hello")
.Description($"Translates from>to text. From the given language to the destiation language. | {Module.Prefix}trans en>fr Hello")
.Parameter("langs", ParameterType.Required)
.Parameter("text", ParameterType.Unparsed)
.Do(TranslateFunc());

View File

@ -71,7 +71,7 @@ namespace NadekoBot.Modules.Trello
cgb.CreateCommand(Prefix + "bind")
.Description("Bind a trello bot to a single channel. " +
"You will receive notifications from your board when something is added or edited." +
"\n**Usage**: bind [board_id]")
" | bind [board_id]")
.Parameter("board_id", Discord.Commands.ParameterType.Required)
.Do(async e =>
{

View File

@ -18,7 +18,7 @@ namespace NadekoBot.Modules.Utility.Commands
{
cgb.CreateCommand(Module.Prefix + "serverinfo")
.Alias(Module.Prefix + "sinfo")
.Description($"Shows info about the server the bot is on. If no channel is supplied, it defaults to current one.\n**Usage**:{Module.Prefix}sinfo Some Server")
.Description($"Shows info about the server the bot is on. If no channel is supplied, it defaults to current one. |{Module.Prefix}sinfo Some Server")
.Parameter("server", ParameterType.Optional)
.Do(async e =>
{
@ -49,7 +49,7 @@ namespace NadekoBot.Modules.Utility.Commands
cgb.CreateCommand(Module.Prefix + "channelinfo")
.Alias(Module.Prefix + "cinfo")
.Description($"Shows info about the channel. If no channel is supplied, it defaults to current one.\n**Usage**:{Module.Prefix}cinfo #some-channel")
.Description($"Shows info about the channel. If no channel is supplied, it defaults to current one. |{Module.Prefix}cinfo #some-channel")
.Parameter("channel", ParameterType.Optional)
.Do(async e =>
{
@ -71,7 +71,7 @@ namespace NadekoBot.Modules.Utility.Commands
cgb.CreateCommand(Module.Prefix + "userinfo")
.Alias(Module.Prefix + "uinfo")
.Description($"Shows info about the user. If no user is supplied, it defaults a user running the command.\n**Usage**:{Module.Prefix}uinfo @SomeUser")
.Description($"Shows info about the user. If no user is supplied, it defaults a user running the command. |{Module.Prefix}uinfo @SomeUser")
.Parameter("user", ParameterType.Optional)
.Do(async e =>
{

View File

@ -88,7 +88,7 @@ namespace NadekoBot.Modules.Utility.Commands
.Description("Sends a message to you or a channel after certain amount of time. " +
"First argument is me/here/'channelname'. Second argument is time in a descending order (mo>w>d>h>m) example: 1w5d3h10m. " +
"Third argument is a (multiword)message. " +
"\n**Usage**: `.remind me 1d5h Do something` or `.remind #general Start now!`")
" | `.remind me 1d5h Do something` or `.remind #general Start now!`")
.Parameter("meorchannel", ParameterType.Required)
.Parameter("time", ParameterType.Required)
.Parameter("message", ParameterType.Unparsed)

View File

@ -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")

View File

@ -42,7 +42,7 @@ namespace NadekoBot
public static string BotMention { get; set; } = "";
public static bool Ready { get; set; } = false;
private static Channel OwnerPrivateChannel { get; set; }
private static List<Channel> OwnerPrivateChannels { get; set; }
private static void Main()
{
@ -196,7 +196,7 @@ namespace NadekoBot
return;
}
#if NADEKO_RELEASE
await Task.Delay(100000).ConfigureAwait(false);
await Task.Delay(120000).ConfigureAwait(false);
#else
await Task.Delay(1000).ConfigureAwait(false);
#endif
@ -205,15 +205,19 @@ namespace NadekoBot
Console.WriteLine(await NadekoStats.Instance.GetStats().ConfigureAwait(false));
Console.WriteLine("-----------------");
OwnerPrivateChannels = new List<Channel>(Creds.OwnerIds.Length);
foreach (var id in Creds.OwnerIds)
{
try
{
OwnerPrivateChannel = await Client.CreatePrivateChannel(Creds.OwnerIds[0]).ConfigureAwait(false);
OwnerPrivateChannels.Add(await Client.CreatePrivateChannel(id).ConfigureAwait(false));
}
catch
{
Console.WriteLine("Failed creating private channel with the first owner listed in credentials.json");
Console.WriteLine($"Failed creating private channel with the owner {id} listed in credentials.json");
}
}
Client.ClientAPI.SendingRequest += (s, e) =>
{
var request = e.Request as Discord.API.Client.Rest.SendMessageRequest;
@ -234,8 +238,18 @@ namespace NadekoBot
public static async Task SendMessageToOwner(string message)
{
if (Config.ForwardMessages && OwnerPrivateChannel != null)
await OwnerPrivateChannel.SendMessage(message).ConfigureAwait(false);
if (Config.ForwardMessages && OwnerPrivateChannels.Any())
if (Config.ForwardToAllOwners)
OwnerPrivateChannels.ForEach(async c =>
{
try { await c.SendMessage(message).ConfigureAwait(false); } catch { }
});
else
{
var c = OwnerPrivateChannels.FirstOrDefault();
if (c != null)
await c.SendMessage(message).ConfigureAwait(false);
}
}
private static bool repliedRecently = false;
@ -248,8 +262,8 @@ namespace NadekoBot
if (ConfigHandler.IsBlackListed(e))
return;
if (Config.ForwardMessages && !NadekoBot.Creds.OwnerIds.Contains(e.User.Id) && OwnerPrivateChannel != null)
await OwnerPrivateChannel.SendMessage(e.User + ": ```\n" + e.Message.Text + "\n```").ConfigureAwait(false);
if (Config.ForwardMessages && !NadekoBot.Creds.OwnerIds.Contains(e.User.Id) && OwnerPrivateChannels.Any())
await SendMessageToOwner(e.User + ": ```\n" + e.Message.Text + "\n```").ConfigureAwait(false);
if (repliedRecently) return;

View File

@ -144,6 +144,7 @@
<Compile Include="Classes\FlowersHandler.cs" />
<Compile Include="Modules\Conversations\Commands\RipCommand.cs" />
<Compile Include="Modules\CustomReactions\CustomReactions.cs" />
<Compile Include="Modules\Music\Classes\PlaylistFullException.cs" />
<Compile Include="Modules\Programming\Commands\HaskellRepl.cs" />
<Compile Include="Modules\Programming\ProgrammingModule.cs" />
<Compile Include="Modules\Searches\Commands\EvalCommand.cs" />

View File

@ -3,25 +3,14 @@ using NadekoBot.Extensions;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization;
namespace NadekoBot.Classes.JSONModels
{
public class Configuration
{
public bool DontJoinServers { get; set; } = false;
public bool ForwardMessages { get; set; } = true;
public bool IsRotatingStatus { get; set; } = false;
public int BufferSize { get; set; } = 4.MiB();
[JsonIgnore]
public List<Quote> Quotes { get; set; } = new List<Quote>();
[JsonIgnore]
public List<PokemonType> PokemonTypes { get; set; } = new List<PokemonType>();
public string RemindMessageFormat { get; set; } = "❗⏰**I've been told to remind you to '%message%' now by %user%.**⏰❗";
public Dictionary<string, List<string>> CustomReactions { get; set; } = new Dictionary<string, List<string>>()
public static readonly Dictionary<string, List<string>> DefaultCustomReactions = new Dictionary<string, List<string>>
{
{@"\o\", new List<string>()
{ "/o/" } },
@ -93,6 +82,22 @@ namespace NadekoBot.Classes.JSONModels
} }
};
public bool DontJoinServers { get; set; } = false;
public bool ForwardMessages { get; set; } = true;
public bool ForwardToAllOwners { get; set; } = false;
public bool IsRotatingStatus { get; set; } = false;
public int BufferSize { get; set; } = 4.MiB();
public List<Quote> Quotes { get; set; } = new List<Quote>();
[JsonIgnore]
public List<PokemonType> PokemonTypes { get; set; } = new List<PokemonType>();
public string RemindMessageFormat { get; set; } = "❗⏰**I've been told to remind you to '%message%' now by %user%.**⏰❗";
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public Dictionary<string, List<string>> CustomReactions { get; set; }
public List<string> RotatingStatuses { get; set; } = new List<string>();
public CommandPrefixesModel CommandPrefixes { get; set; } = new CommandPrefixesModel();
public HashSet<ulong> ServerBlacklist { get; set; } = new HashSet<ulong>();
@ -104,6 +109,22 @@ namespace NadekoBot.Classes.JSONModels
143515953525817344
};
[OnDeserialized]
internal void OnDeserialized(StreamingContext context)
{
if (CustomReactions == null)
{
CustomReactions = DefaultCustomReactions;
}
}
[OnSerializing]
internal void OnSerializing(StreamingContext context)
{
if (CustomReactions == null)
{
CustomReactions = DefaultCustomReactions;
}
}
public string[] _8BallResponses { get; set; } =
{

View File

@ -1,8 +1,10 @@
{
"DontJoinServers": false,
"ForwardMessages": true,
"ForwardToAllOwners": false,
"IsRotatingStatus": false,
"BufferSize": 4194304,
"Quotes": [],
"RemindMessageFormat": "❗⏰**I've been told to remind you to '%message%' now by %user%.**⏰❗",
"CustomReactions": {
"\\o\\": [

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -1,36 +0,0 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Tests")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Tests")]
[assembly: AssemblyCopyright("Copyright © 2016")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("45b2545d-c612-4919-b34c-d65ea1371c51")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@ -1,45 +0,0 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Collections.Generic;
using static NadekoBot.Modules.Gambling.Helpers.Cards;
namespace Tests
{
[TestClass]
public class TestCards
{
[TestMethod]
public void TestHandValues()
{
var setting1 = new List<Card> {
new Card(CardSuit.Clubs,10),
new Card(CardSuit.Clubs,10),
new Card(CardSuit.Clubs,10),
new Card(CardSuit.Clubs,11),
new Card(CardSuit.Diamonds,12),
};
var result1 = "Three Of A Kind";
var setting2 = new List<Card> {
new Card(CardSuit.Clubs,1),
new Card(CardSuit.Hearts,2),
new Card(CardSuit.Clubs,3),
new Card(CardSuit.Spades,4),
new Card(CardSuit.Diamonds,5),
};
var result2 = "Straight";
var setting3 = new List<Card> {
new Card(CardSuit.Diamonds,10),
new Card(CardSuit.Diamonds,11),
new Card(CardSuit.Diamonds,12),
new Card(CardSuit.Diamonds,13),
new Card(CardSuit.Diamonds,1),
};
var result3 = "Royal Flush";
Assert.AreEqual(GetHandValue(setting1), result1);
Assert.AreEqual(GetHandValue(setting2), result2);
Assert.AreEqual(GetHandValue(setting3), result3);
}
}
}

View File

@ -1,90 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{45B2545D-C612-4919-B34C-D65EA1371C51}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Tests</RootNamespace>
<AssemblyName>Tests</AssemblyName>
<TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
<ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages</ReferencePath>
<IsCodedUITest>False</IsCodedUITest>
<TestProjectType>UnitTest</TestProjectType>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
</ItemGroup>
<Choose>
<When Condition="('$(VisualStudioVersion)' == '10.0' or '$(VisualStudioVersion)' == '') and '$(TargetFrameworkVersion)' == 'v3.5'">
<ItemGroup>
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
</ItemGroup>
</When>
<Otherwise>
<ItemGroup>
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework" />
</ItemGroup>
</Otherwise>
</Choose>
<ItemGroup>
<Compile Include="TestCards.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\NadekoBot\NadekoBot.csproj">
<Project>{27a886f5-cdda-4f4a-81ee-6dafcce9de46}</Project>
<Name>NadekoBot</Name>
</ProjectReference>
</ItemGroup>
<Choose>
<When Condition="'$(VisualStudioVersion)' == '10.0' And '$(IsCodedUITest)' == 'True'">
<ItemGroup>
<Reference Include="Microsoft.VisualStudio.QualityTools.CodedUITestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>False</Private>
</Reference>
<Reference Include="Microsoft.VisualStudio.TestTools.UITest.Common, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>False</Private>
</Reference>
<Reference Include="Microsoft.VisualStudio.TestTools.UITest.Extension, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>False</Private>
</Reference>
<Reference Include="Microsoft.VisualStudio.TestTools.UITesting, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>False</Private>
</Reference>
</ItemGroup>
</When>
</Choose>
<Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@ -2,7 +2,7 @@
######You can donate on paypal: `nadekodiscordbot@gmail.com` or Bitcoin `17MZz1JAqME39akMLrVT4XBPffQJ2n1EPa`
#NadekoBot List Of Commands
Version: `NadekoBot v0.9.6030.3793`
Version: `NadekoBot v0.9.6036.32870`
### Help
Command and aliases | Description | Usage
----------------|--------------|-------
@ -45,7 +45,7 @@ Command and aliases | Description | Usage
`.iam` | Adds a role to you that you choose. Role must be on a list of self-assignable roles. | .iam Gamer
`.iamnot`, `.iamn` | Removes a role to you that you choose. Role must be on a list of self-assignable roles. | .iamn Gamer
`.addcustreact`, `.acr` | Add a custom reaction. Guide here: <https://github.com/Kwoth/NadekoBot/wiki/Custom-Reactions> **Bot Owner Only!** | .acr "hello" I love saying hello to %user%
`.listcustreact`, `.lcr` | Lists all current custom reactions (paginated with 30 commands per page). | .lcr 1
`.listcustreact`, `.lcr` | Lists custom reactions (paginated with 30 commands per page). Use 'all' instead of page number to get all custom reactions DM-ed to you. | .lcr 1
`.showcustreact`, `.scr` | Shows all possible responses from a single custom reaction. | .scr %mention% bb
`.editcustreact`, `.ecr` | Edits a custom reaction, arguments are custom reactions name, index to change, and a (multiword) message **Bot Owner Only** | `.ecr "%mention% disguise" 2 Test 123`
`.delcustreact`, `.dcr` | Deletes a custom reaction with given name (and index)
@ -126,24 +126,24 @@ Command and aliases | Description | Usage
`;roleperms`, `;rp` | Shows banned permissions for a certain role. No argument means for everyone. | ;rp AwesomeRole
`;chnlperms`, `;cp` | Shows banned permissions for a certain channel. No argument means for this channel. | ;cp #dev
`;userperms`, `;up` | Shows banned permissions for a certain user. No argument means for yourself. | ;up Kwoth
`;srvrmdl`, `;sm` | Sets a module's permission at the server level. | ;sm [module_name] enable
`;srvrcmd`, `;sc` | Sets a command's permission at the server level. | ;sc [command_name] disable
`;rolemdl`, `;rm` | Sets a module's permission at the role level. | ;rm [module_name] enable [role_name]
`;rolecmd`, `;rc` | Sets a command's permission at the role level. | ;rc [command_name] disable [role_name]
`;chnlmdl`, `;cm` | Sets a module's permission at the channel level. | ;cm [module_name] enable [channel_name]
`;chnlcmd`, `;cc` | Sets a command's permission at the channel level. | ;cc [command_name] enable [channel_name]
`;usrmdl`, `;um` | Sets a module's permission at the user level. | ;um [module_name] enable [user_name]
`;usrcmd`, `;uc` | Sets a command's permission at the user level. | ;uc [command_name] enable [user_name]
`;srvrmdl`, `;sm` | Sets a module's permission at the server level. | ;sm "module name" enable
`;srvrcmd`, `;sc` | Sets a command's permission at the server level. | ;sc "command name" disable
`;rolemdl`, `;rm` | Sets a module's permission at the role level. | ;rm "module name" enable MyRole
`;rolecmd`, `;rc` | Sets a command's permission at the role level. | ;rc "command name" disable MyRole
`;chnlmdl`, `;cm` | Sets a module's permission at the channel level. | ;cm "module name" enable SomeChannel
`;chnlcmd`, `;cc` | Sets a command's permission at the channel level. | ;cc "command name" enable SomeChannel
`;usrmdl`, `;um` | Sets a module's permission at the user level. | ;um "module name" enable SomeUsername
`;usrcmd`, `;uc` | Sets a command's permission at the user level. | ;uc "command name" enable SomeUsername
`;allsrvrmdls`, `;asm` | Sets permissions for all modules at the server level. | ;asm [enable/disable]
`;allsrvrcmds`, `;asc` | Sets permissions for all commands from a certain module at the server level. | ;asc [module_name] [enable/disable]
`;allchnlmdls`, `;acm` | Sets permissions for all modules at the channel level. | ;acm [enable/disable] [channel_name]
`;allchnlcmds`, `;acc` | Sets permissions for all commands from a certain module at the channel level. | ;acc [module_name] [enable/disable] [channel_name]
`;allrolemdls`, `;arm` | Sets permissions for all modules at the role level. | ;arm [enable/disable] [role_name]
`;allrolecmds`, `;arc` | Sets permissions for all commands from a certain module at the role level. | ;arc [module_name] [enable/disable] [role_name]
`;allsrvrcmds`, `;asc` | Sets permissions for all commands from a certain module at the server level. | ;asc "module name" [enable/disable]
`;allchnlmdls`, `;acm` | Sets permissions for all modules at the channel level. | ;acm [enable/disable] SomeChannel
`;allchnlcmds`, `;acc` | Sets permissions for all commands from a certain module at the channel level. | ;acc "module name" [enable/disable] SomeChannel
`;allrolemdls`, `;arm` | Sets permissions for all modules at the role level. | ;arm [enable/disable] MyRole
`;allrolecmds`, `;arc` | Sets permissions for all commands from a certain module at the role level. | ;arc "module name" [enable/disable] MyRole
`;ubl` | Blacklists a mentioned user. | ;ubl [user_mention]
`;uubl` | Unblacklists a mentioned user. | ;uubl [user_mention]
`;cbl` | Blacklists a mentioned channel (#general for example). | ;cbl [channel_mention]
`;cubl` | Unblacklists a mentioned channel (#general for example). | ;cubl [channel_mention]
`;cbl` | Blacklists a mentioned channel (#general for example). | ;cbl #some_channel
`;cubl` | Unblacklists a mentioned channel (#general for example). | ;cubl #some_channel
`;sbl` | Blacklists a server by a name or id (#general for example). **BOT OWNER ONLY** | ;sbl [servername/serverid]
### Conversations
@ -153,7 +153,6 @@ Command and aliases | Description | Usage
`...` | Shows a random quote with a specified name. | .. abc
`..qdel`, `..quotedelete` | Deletes all quotes with the specified keyword. You have to either be bot owner or the creator of the quote to delete it. | `..qdel abc`
`@BotName rip` | Shows a grave image of someone with a start year | @NadekoBot rip @Someone 2000
`@BotName uptime` | Shows how long Nadeko has been running for.
`@BotName die` | Works only for the owner. Shuts the bot down.
`@BotName do you love me` | Replies with positive answer only to the bot owner.
`@BotName how are you`, `@BotName how are you?` | Replies positive only if bot owner is online.
@ -190,7 +189,7 @@ Command and aliases | Description | Usage
`>pollend` | Stops active poll on this server and prints the results in this channel.
`>pick` | Picks a flower planted in this channel.
`>plant` | Spend a flower to plant it in this channel. (If bot is restarted or crashes, flower will be lost)
`>gencurrency`, `>gc` | Toggles currency generation on this channel. Every posted message will have 2% chance to spawn a NadekoFlower. Requires Manage Messages permission. | `>gc`
`>gencurrency`, `>gc` | Toggles currency generation on this channel. Every posted message will have 2% chance to spawn a NadekoFlower. Optional parameter cooldown time in minutes, 5 minutes by default. Requires Manage Messages permission. | `>gc` or `>gc 60`
`>leet` | Converts a text to leetspeak with 6 (1-6) severity levels | >leet 3 Hello
`>choose` | Chooses a thing from a list of things | >choose Get up;Sleep;Sleep more
`>8ball` | Ask the 8ball a yes/no question.
@ -205,15 +204,16 @@ Command and aliases | Description | Usage
`!m destroy`, `!m d` | Completely stops the music and unbinds the bot from the channel. (may cause weird behaviour) | `!m d`
`!m pause`, `!m p` | Pauses or Unpauses the song. | `!m p`
`!m queue`, `!m q`, `!m yq` | Queue a song using keywords or a link. Bot will join your voice channel.**You must be in a voice channel**. | `!m q Dream Of Venice`
`!m soundcloudqueue`, `!m sq` | Queue a soundcloud song using keywords. Bot will join your voice channel.**You must be in a voice channel**. | `!m sq Dream Of Venice`
`!m listqueue`, `!m lq` | Lists 15 currently queued songs per page. Default page is 1. | `!m lq` or `!m lq 2`
`!m nowplaying`, `!m np` | Shows the song currently playing. | `!m np`
`!m volume`, `!m vol` | Sets the music volume 0-100% | `!m vol 50`
`!m defvol`, `!m dv` | Sets the default music volume when music playback is started (0-100). Persists through restarts. | `!m dv 80`
`!m mute`, `!m min` | Sets the music volume to 0% | `!m min`
`!m max` | Sets the music volume to 100% (real max is actually 150%). | `!m max`
`!m max` | Sets the music volume to 100%. | `!m max`
`!m half` | Sets the music volume to 50%. | `!m half`
`!m shuffle`, `!m sh` | Shuffles the current playlist. | `!m sh`
`!m playlist`, `!m pl` | Queues up to 50 songs from a youtube playlist specified by a link, or keywords. | `!m pl playlist link or name`
`!m playlist`, `!m pl` | Queues up to 500 songs from a youtube playlist specified by a link, or keywords. | `!m pl playlist link or name`
`!m soundcloudpl`, `!m scpl` | Queue a soundcloud playlist using a link. | `!m scpl https://soundcloud.com/saratology/sets/symphony`
`!m localplaylst`, `!m lopl` | Queues all songs from a directory. **Bot Owner Only!** | `!m lopl C:/music/classical`
`!m radio`, `!m ra` | Queues a radio stream from a link. It can be a direct mp3 radio stream, .m3u, .pls .asx or .xspf | `!m ra radio link here`
@ -221,6 +221,7 @@ Command and aliases | Description | Usage
`!m move`, `!m mv` | Moves the bot to your voice channel. (works only if music is already playing) | `!m mv`
`!m remove`, `!m rm` | Remove a song by its # in the queue, or 'all' to remove whole queue. | `!m rm 5`
`!m movesong`, `!m ms` | Moves a song from one position to another. | `!m ms` 5>3
`!m setmaxqueue`, `!m smq` | Sets a maximum queue size. Supply 0 or no argument to have no limit. | `!m smq` 50 or `!m smq`
`!m cleanup` | Cleans up hanging voice connections. **Bot Owner Only!** | `!m cleanup`
`!m reptcursong`, `!m rcs` | Toggles repeat of current song. | `!m rcs`
`!m rpeatplaylst`, `!m rpl` | Toggles repeat of all songs in the queue (every song that finishes is added to the end of the queue). | `!m rpl`
@ -253,7 +254,7 @@ Command and aliases | Description | Usage
`~osu b` | Shows information about an osu beatmap. | ~osu b https://osu.ppy.sh/s/127712
`~osu top5` | Displays a user's top 5 plays. | ~osu top5 Name
`~pokemon`, `~poke` | Searches for a pokemon.
`~pokemonability`, `~pokab` | Searches for a pokemon ability.
`~pokemonability`, `~pokeab` | Searches for a pokemon ability.
`~memelist` | Pulls a list of memes you can use with `~memegen` from http://memegen.link/templates/
`~memegen` | Generates a meme from memelist with top and bottom text. | `~memegen biw "gets iced coffee" "in the winter"`
`~we` | Shows weather data for a specified city and a country. BOTH ARE REQUIRED. Use country abbrevations. | ~we Moscow RF
@ -301,14 +302,16 @@ Command and aliases | Description | Usage
`,startwar`, `,sw` | Starts a war with a given number.
`,listwar`, `,lw` | Shows the active war claims by a number. Shows all wars in a short way if no number is specified. | ,lw [war_number] or ,lw
`,claim`, `,call`, `,c` | Claims a certain base from a certain war. You can supply a name in the third optional argument to claim in someone else's place. | ,call [war_number] [base_number] [optional_other_name]
`,claimfinish`, `,cf` | Finish your claim if you destroyed a base. Optional second argument finishes for someone else. | ,cf [war_number] [optional_other_name]
`,claimfinish`, `,cf`, `,cf3`, `,claimfinish3` | Finish your claim with 3 stars if you destroyed a base. Optional second argument finishes for someone else. | ,cf [war_number] [optional_other_name]
`,claimfinish2`, `,cf2` | Finish your claim with 2 stars if you destroyed a base. Optional second argument finishes for someone else. | ,cf [war_number] [optional_other_name]
`,claimfinish1`, `,cf1` | Finish your claim with 1 stars if you destroyed a base. Optional second argument finishes for someone else. | ,cf [war_number] [optional_other_name]
`,unclaim`, `,uncall`, `,uc` | Removes your claim from a certain war. Optional second argument denotes a person in whos place to unclaim | ,uc [war_number] [optional_other_name]
`,endwar`, `,ew` | Ends the war with a given index. | ,ew [war_number]
### Pokegame
Command and aliases | Description | Usage
----------------|--------------|-------
`>attack` | Attacks a target with the given move
`>attack` | Attacks a target with the given move. Use `>movelist` to see a list of moves your type can use. | `>attack "vine whip" @someguy`
`>movelist`, `>ml` | Lists the moves you are able to use
`>heal` | Heals someone. Revives those that fainted. Costs a NadekoFlower | >revive @someone
`>type` | Get the poketype of the target. | >type @someone

View File

@ -1 +0,0 @@
fb079285-44f2-47d3-b55c-d748701c36ee