Merge pull request #424 from Kwoth/dev

0.99.9
This commit is contained in:
Master Kwoth 2016-07-20 17:29:34 +02:00 committed by GitHub
commit 06a5da18c2
72 changed files with 1127 additions and 785 deletions

3
.gitignore vendored
View File

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

View File

@ -33,7 +33,24 @@ ________________________________________________________________________________
________________________________________________________________________________ ________________________________________________________________________________
#### Setting Up NadekoBot For Music #### 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 1) Google Account
2) Soundcloud Account (if you want soundcloud support) 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) - 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 <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> </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)** **3)**
<pre><code class="language-bash">apt-get install mono-devel <pre><code class="language-bash">apt-get install mono-devel
</code></pre> </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 <pre><code class="language-bash">sudo apt-get install libopus-dev
</code></pre> </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 ######FFMPEG
**6)** **6)**
@ -87,6 +108,20 @@ Note if the command is not be initiated, hit **Enter**
*Before executing* `sudo apt-get install ffmpeg` *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 ######Uncomplicated Firewall UFW
**7)** **7)**

View File

@ -1,7 +1,7 @@
 
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14 # Visual Studio 14
VisualStudioVersion = 14.0.25123.0 VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NadekoBot", "NadekoBot\NadekoBot.csproj", "{27A886F5-CDDA-4F4A-81EE-6DAFCCE9DE46}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NadekoBot", "NadekoBot\NadekoBot.csproj", "{27A886F5-CDDA-4F4A-81EE-6DAFCCE9DE46}"
EndProject EndProject
@ -13,13 +13,11 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Discord.Net.Modules", "disc
EndProject 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}" 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 EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{45B2545D-C612-4919-B34C-D65EA1371C51}"
EndProject
Global Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution 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*{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*{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 discord.net\src\Discord.Net.Shared\Discord.Net.Shared.projitems*{8d71a857-879a-4a10-859e-5ff824ed6688}*SharedItemsImports = 4
EndGlobalSection EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution 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}.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.ActiveCfg = Release|Any CPU
{1B5603B4-6F8F-4289-B945-7BAAE523D740}.Release|Any CPU.Build.0 = 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 EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

View File

@ -21,12 +21,12 @@ namespace NadekoBot.Classes
if (silent) if (silent)
return; return;
var flows = amount +" " + NadekoBot.Config.CurrencySign; var flows = amount + " " + NadekoBot.Config.CurrencySign;
await u.SendMessage("👑Congratulations!👑\nYou received: " + flows).ConfigureAwait(false); 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) if (amount <= 0)
return false; return false;
@ -42,6 +42,11 @@ namespace NadekoBot.Classes
UserId = (long)u.Id, UserId = (long)u.Id,
Value = -amount, Value = -amount,
}); });
if (silent)
return true;
await u.SendMessage(string.Format(message,amount,NadekoBot.Config.CurrencySign)).ConfigureAwait(false);
return true; return true;
} }
} }

View File

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

View File

@ -27,7 +27,13 @@ namespace NadekoBot.Classes
{ {
configs = JsonConvert configs = JsonConvert
.DeserializeObject<ConcurrentDictionary<ulong, ServerSpecificConfig>>( .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) 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")] [JsonProperty("LogPresenceChannel")]
private ulong? logPresenceChannel = null; private ulong? logPresenceChannel = null;
[JsonIgnore] [JsonIgnore]
@ -136,6 +157,8 @@ namespace NadekoBot.Classes
} }
} }
[JsonIgnore] [JsonIgnore]
private ulong autoAssignedRole = 0; private ulong autoAssignedRole = 0;
public ulong AutoAssignedRole { public ulong AutoAssignedRole {
@ -148,8 +171,8 @@ namespace NadekoBot.Classes
} }
[JsonIgnore] [JsonIgnore]
private ObservableCollection<ulong> generateCurrencyChannels; private ObservableConcurrentDictionary<ulong, int> generateCurrencyChannels;
public ObservableCollection<ulong> GenerateCurrencyChannels { public ObservableConcurrentDictionary<ulong, int> GenerateCurrencyChannels {
get { return generateCurrencyChannels; } get { return generateCurrencyChannels; }
set { set {
generateCurrencyChannels = value; generateCurrencyChannels = value;
@ -173,6 +196,19 @@ namespace NadekoBot.Classes
} }
} }
[JsonIgnore]
private bool exclusiveSelfAssignedRoles = false;
public bool ExclusiveSelfAssignedRoles
{
get { return exclusiveSelfAssignedRoles; }
set
{
exclusiveSelfAssignedRoles = value;
if (!SpecificConfigurations.Instantiated) return;
OnPropertyChanged();
}
}
[JsonIgnore] [JsonIgnore]
private ObservableCollection<StreamNotificationConfig> observingStreams; private ObservableCollection<StreamNotificationConfig> observingStreams;
@ -204,8 +240,9 @@ namespace NadekoBot.Classes
{ {
ListOfSelfAssignableRoles = new ObservableCollection<ulong>(); ListOfSelfAssignableRoles = new ObservableCollection<ulong>();
ObservingStreams = new ObservableCollection<StreamNotificationConfig>(); ObservingStreams = new ObservableCollection<StreamNotificationConfig>();
GenerateCurrencyChannels = new ObservableCollection<ulong>(); GenerateCurrencyChannels = new ObservableConcurrentDictionary<ulong, int>();
VoiceChannelLog = new ObservableConcurrentDictionary<ulong, ulong>(); VoiceChannelLog = new ObservableConcurrentDictionary<ulong, ulong>();
LogserverIgnoreChannels = new ObservableCollection<ulong>();
} }
public event PropertyChangedEventHandler PropertyChanged = delegate { SpecificConfigurations.Default.Save(); }; public event PropertyChangedEventHandler PropertyChanged = delegate { SpecificConfigurations.Default.Save(); };
@ -239,7 +276,7 @@ namespace NadekoBot.Classes
public override int GetHashCode() 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") 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("user_name", ParameterType.Required)
.Parameter("role_name", ParameterType.Unparsed) .Parameter("role_name", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.CanManageRoles) .AddCheck(SimpleCheckers.CanManageRoles)
@ -133,7 +133,7 @@ namespace NadekoBot.Modules.Administration
}); });
cgb.CreateCommand(Prefix + "removerole").Alias(Prefix + "rr") 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("user_name", ParameterType.Required)
.Parameter("role_name", ParameterType.Unparsed) .Parameter("role_name", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.CanManageRoles) .AddCheck(SimpleCheckers.CanManageRoles)
@ -171,7 +171,7 @@ namespace NadekoBot.Modules.Administration
cgb.CreateCommand(Prefix + "renamerole") cgb.CreateCommand(Prefix + "renamerole")
.Alias(Prefix + "renr") .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("r1", ParameterType.Required)
.Parameter("r2", ParameterType.Required) .Parameter("r2", ParameterType.Required)
.AddCheck(new SimpleCheckers.ManageRoles()) .AddCheck(new SimpleCheckers.ManageRoles())
@ -204,7 +204,7 @@ namespace NadekoBot.Modules.Administration
}); });
cgb.CreateCommand(Prefix + "removeallroles").Alias(Prefix + "rar") 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) .Parameter("user_name", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.CanManageRoles) .AddCheck(SimpleCheckers.CanManageRoles)
.Do(async e => .Do(async e =>
@ -253,7 +253,7 @@ namespace NadekoBot.Modules.Administration
.Parameter("r", ParameterType.Optional) .Parameter("r", ParameterType.Optional)
.Parameter("g", ParameterType.Optional) .Parameter("g", ParameterType.Optional)
.Parameter("b", 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 => .Do(async e =>
{ {
if (!e.User.ServerPermissions.ManageRoles) if (!e.User.ServerPermissions.ManageRoles)
@ -298,7 +298,7 @@ namespace NadekoBot.Modules.Administration
cgb.CreateCommand(Prefix + "ban").Alias(Prefix + "b") cgb.CreateCommand(Prefix + "ban").Alias(Prefix + "b")
.Parameter("user", ParameterType.Required) .Parameter("user", ParameterType.Required)
.Parameter("msg", ParameterType.Unparsed) .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 => .Do(async e =>
{ {
var msg = e.GetArg("msg"); var msg = e.GetArg("msg");
@ -333,7 +333,7 @@ namespace NadekoBot.Modules.Administration
cgb.CreateCommand(Prefix + "softban").Alias(Prefix + "sb") cgb.CreateCommand(Prefix + "softban").Alias(Prefix + "sb")
.Parameter("user", ParameterType.Required) .Parameter("user", ParameterType.Required)
.Parameter("msg", ParameterType.Unparsed) .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 => .Do(async e =>
{ {
var msg = e.GetArg("msg"); var msg = e.GetArg("msg");
@ -592,7 +592,7 @@ namespace NadekoBot.Modules.Administration
cgb.CreateCommand(Prefix + "settopic") cgb.CreateCommand(Prefix + "settopic")
.Alias(Prefix + "st") .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()) .AddCheck(SimpleCheckers.ManageChannels())
.Parameter("topic", ParameterType.Unparsed) .Parameter("topic", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
@ -628,27 +628,18 @@ namespace NadekoBot.Modules.Administration
cgb.CreateCommand(Prefix + "prune") cgb.CreateCommand(Prefix + "prune")
.Alias(Prefix + "clr") .Alias(Prefix + "clr")
.Description( .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("user_or_num", ParameterType.Optional)
.Parameter("num", ParameterType.Optional) .Parameter("num", ParameterType.Optional)
.Do(async e => .Do(async e =>
{ {
Message[] msgs;
if (string.IsNullOrWhiteSpace(e.GetArg("user_or_num"))) // if nothing is set, clear nadeko's messages, no permissions required if (string.IsNullOrWhiteSpace(e.GetArg("user_or_num"))) // if nothing is set, clear nadeko's messages, no permissions required
{ {
await Task.Run(async () => msgs = (await e.Channel.DownloadMessages(100).ConfigureAwait(false)).Where(m => m.User.Id == e.Server.CurrentUser.Id).ToArray();
{ if (!msgs.Any())
var msgs = (await e.Channel.DownloadMessages(100).ConfigureAwait(false)).Where(m => m.User.Id == e.Server.CurrentUser.Id); return;
foreach (var m in msgs) await e.Channel.DeleteMessages(msgs).ConfigureAwait(false);
{
try
{
await m.Delete().ConfigureAwait(false);
}
catch { }
await Task.Delay(100).ConfigureAwait(false);
}
}).ConfigureAwait(false);
return; return;
} }
if (!e.User.GetPermissions(e.Channel).ManageMessages) if (!e.User.GetPermissions(e.Channel).ManageMessages)
@ -665,11 +656,7 @@ namespace NadekoBot.Modules.Administration
if (val <= 0) if (val <= 0)
return; return;
val++; val++;
foreach (var msg in await e.Channel.DownloadMessages(val).ConfigureAwait(false)) await e.Channel.DeleteMessages((await e.Channel.DownloadMessages(val).ConfigureAwait(false)).ToArray()).ConfigureAwait(false);
{
await msg.Delete().ConfigureAwait(false);
await Task.Delay(100).ConfigureAwait(false);
}
return; return;
} }
//else if first argument is user //else if first argument is user
@ -679,20 +666,10 @@ namespace NadekoBot.Modules.Administration
val = 100; val = 100;
if (!int.TryParse(e.GetArg("num"), out val)) if (!int.TryParse(e.GetArg("num"), out val))
val = 100; val = 100;
await Task.Run(async () => msgs = (await e.Channel.DownloadMessages(100).ConfigureAwait(false)).Where(m => m.User.Id == usr.Id).Take(val).ToArray();
{ if (!msgs.Any())
var msgs = (await e.Channel.DownloadMessages(100).ConfigureAwait(false)).Where(m => m.User.Id == usr.Id).Take(val); return;
foreach (var m in msgs) await e.Channel.DeleteMessages(msgs).ConfigureAwait(false);
{
try
{
await m.Delete().ConfigureAwait(false);
}
catch { }
await Task.Delay(100).ConfigureAwait(false);
}
}).ConfigureAwait(false);
}); });
cgb.CreateCommand(Prefix + "die") cgb.CreateCommand(Prefix + "die")
@ -719,7 +696,7 @@ namespace NadekoBot.Modules.Administration
cgb.CreateCommand(Prefix + "newavatar") cgb.CreateCommand(Prefix + "newavatar")
.Alias(Prefix + "setavatar") .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) .Parameter("img", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.OwnerOnly()) .AddCheck(SimpleCheckers.OwnerOnly())
.Do(async e => .Do(async e =>
@ -750,7 +727,7 @@ namespace NadekoBot.Modules.Administration
}); });
cgb.CreateCommand(Prefix + "send") 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("ids", ParameterType.Required)
.Parameter("msg", ParameterType.Unparsed) .Parameter("msg", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.OwnerOnly()) .AddCheck(SimpleCheckers.OwnerOnly())
@ -877,7 +854,7 @@ namespace NadekoBot.Modules.Administration
}); });
cgb.CreateCommand(Prefix + "announce") 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) .Parameter("msg", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.OwnerOnly()) .AddCheck(SimpleCheckers.OwnerOnly())
.Do(async e => .Do(async e =>
@ -890,21 +867,6 @@ namespace NadekoBot.Modules.Administration
await e.Channel.SendMessage(":ok:").ConfigureAwait(false); 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") cgb.CreateCommand(Prefix + "savechat")
.Description("Saves a number of messages to a text file and sends it to you. **Bot Owner Only** | `.chatsave 150`") .Description("Saves a number of messages to a text file and sends it to you. **Bot Owner Only** | `.chatsave 150`")
.Parameter("cnt", ParameterType.Required) .Parameter("cnt", ParameterType.Required)
@ -929,7 +891,7 @@ namespace NadekoBot.Modules.Administration
lastmsgId = msgs[msgs.Count - 1].Id; lastmsgId = msgs[msgs.Count - 1].Id;
cnt -= 100; 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 Discord.Commands;
using NadekoBot.Classes; using NadekoBot.Classes;
using NadekoBot.Modules.Permissions.Classes; using NadekoBot.Modules.Permissions.Classes;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
@ -22,7 +23,7 @@ namespace NadekoBot.Modules.Administration.Commands
cgb.CreateCommand(Prefix + "addcustreact") cgb.CreateCommand(Prefix + "addcustreact")
.Alias(Prefix + "acr") .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()) .AddCheck(SimpleCheckers.OwnerOnly())
.Parameter("name", ParameterType.Required) .Parameter("name", ParameterType.Required)
.Parameter("message", ParameterType.Unparsed) .Parameter("message", ParameterType.Unparsed)
@ -46,16 +47,29 @@ namespace NadekoBot.Modules.Administration.Commands
cgb.CreateCommand(Prefix + "listcustreact") cgb.CreateCommand(Prefix + "listcustreact")
.Alias(Prefix + "lcr") .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) .Parameter("num", ParameterType.Required)
.Do(async e => .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; 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); var cmds = GetCustomsOnPage(num - 1);
if (!cmds.Any()) if (!cmds.Any())
{ {
await e.Channel.SendMessage(""); await e.Channel.SendMessage("`There are no custom reactions.`");
} }
else else
{ {
@ -66,7 +80,7 @@ namespace NadekoBot.Modules.Administration.Commands
cgb.CreateCommand(Prefix + "showcustreact") cgb.CreateCommand(Prefix + "showcustreact")
.Alias(Prefix + "scr") .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) .Parameter("name", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -85,7 +99,7 @@ namespace NadekoBot.Modules.Administration.Commands
int i = 1; int i = 1;
foreach (var reaction in items) 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()); await e.Channel.SendMessage(message.ToString());
}); });

View File

@ -51,8 +51,9 @@ namespace NadekoBot.Modules.Administration.Commands
{ {
try try
{ {
var chId = SpecificConfigurations.Default.Of(e.Server.Id).LogServerChannel; var config = SpecificConfigurations.Default.Of(e.Server.Id);
if (chId == null) var chId = config.LogServerChannel;
if (chId == null || config.LogserverIgnoreChannels.Contains(e.After.Id))
return; return;
Channel ch; Channel ch;
if ((ch = e.Server.TextChannels.Where(tc => tc.Id == chId).FirstOrDefault()) == null) if ((ch = e.Server.TextChannels.Where(tc => tc.Id == chId).FirstOrDefault()) == null)
@ -72,8 +73,9 @@ namespace NadekoBot.Modules.Administration.Commands
{ {
try try
{ {
var chId = SpecificConfigurations.Default.Of(e.Server.Id).LogServerChannel; var config = SpecificConfigurations.Default.Of(e.Server.Id);
if (chId == null) var chId = config.LogServerChannel;
if (chId == null || config.LogserverIgnoreChannels.Contains(e.Channel.Id))
return; return;
Channel ch; Channel ch;
if ((ch = e.Server.TextChannels.Where(tc => tc.Id == chId).FirstOrDefault()) == null) if ((ch = e.Server.TextChannels.Where(tc => tc.Id == chId).FirstOrDefault()) == null)
@ -87,8 +89,9 @@ namespace NadekoBot.Modules.Administration.Commands
{ {
try try
{ {
var chId = SpecificConfigurations.Default.Of(e.Server.Id).LogServerChannel; var config = SpecificConfigurations.Default.Of(e.Server.Id);
if (chId == null) var chId = config.LogServerChannel;
if (chId == null || config.LogserverIgnoreChannels.Contains(e.Channel.Id))
return; return;
Channel ch; Channel ch;
if ((ch = e.Server.TextChannels.Where(tc => tc.Id == chId).FirstOrDefault()) == null) 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) if (e.Server == null || e.Channel.IsPrivate || e.User.Id == NadekoBot.Client.CurrentUser.Id)
return; return;
var chId = SpecificConfigurations.Default.Of(e.Server.Id).LogServerChannel; var config = SpecificConfigurations.Default.Of(e.Server.Id);
if (chId == null || e.Channel.Id == chId) var chId = config.LogServerChannel;
if (chId == null || e.Channel.Id == chId || config.LogserverIgnoreChannels.Contains(e.Channel.Id))
return; return;
Channel ch; Channel ch;
if ((ch = e.Server.TextChannels.Where(tc => tc.Id == chId).FirstOrDefault()) == null) 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) if (e.Server == null || e.Channel.IsPrivate || e.User?.Id == NadekoBot.Client.CurrentUser.Id)
return; return;
var chId = SpecificConfigurations.Default.Of(e.Server.Id).LogServerChannel; var config = SpecificConfigurations.Default.Of(e.Server.Id);
if (chId == null || e.Channel.Id == chId) var chId = config.LogServerChannel;
if (chId == null || e.Channel.Id == chId || config.LogserverIgnoreChannels.Contains(e.Channel.Id))
return; return;
Channel ch; Channel ch;
if ((ch = e.Server.TextChannels.Where(tc => tc.Id == chId).FirstOrDefault()) == null) 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) if (e.Server == null || e.Channel.IsPrivate || e.User?.Id == NadekoBot.Client.CurrentUser.Id)
return; return;
var chId = SpecificConfigurations.Default.Of(e.Server.Id).LogServerChannel; var config = SpecificConfigurations.Default.Of(e.Server.Id);
if (chId == null || e.Channel.Id == chId) var chId = config.LogServerChannel;
if (chId == null || e.Channel.Id == chId || config.LogserverIgnoreChannels.Contains(e.Channel.Id))
return; return;
Channel ch; Channel ch;
if ((ch = e.Server.TextChannels.Where(tc => tc.Id == chId).FirstOrDefault()) == null) 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); 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") cgb.CreateCommand(Module.Prefix + "userpresence")
.Description("Starts logging to this channel when someone from the server goes online/offline/idle.") .Description("Starts logging to this channel when someone from the server goes online/offline/idle.")
.AddCheck(SimpleCheckers.ManageServer()) .AddCheck(SimpleCheckers.ManageServer())

View File

@ -73,7 +73,7 @@ namespace NadekoBot.Modules.Administration.Commands
cgb.CreateCommand(Module.Prefix + "repeat") cgb.CreateCommand(Module.Prefix + "repeat")
.Description("Repeat a message every X minutes. If no parameters are specified, " + .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("minutes", ParameterType.Optional)
.Parameter("msg", ParameterType.Unparsed) .Parameter("msg", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.ManageMessages()) .AddCheck(SimpleCheckers.ManageMessages())

View File

@ -15,7 +15,7 @@ namespace NadekoBot.Modules.Administration.Commands
{ {
cgb.CreateCommand(Module.Prefix + "asar") cgb.CreateCommand(Module.Prefix + "asar")
.Description("Adds a role, or list of roles separated by whitespace" + .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) .Parameter("roles", ParameterType.Multiple)
.AddCheck(SimpleCheckers.CanManageRoles) .AddCheck(SimpleCheckers.CanManageRoles)
.Do(async e => .Do(async e =>
@ -74,7 +74,7 @@ namespace NadekoBot.Modules.Administration.Commands
var config = SpecificConfigurations.Default.Of(e.Server.Id); var config = SpecificConfigurations.Default.Of(e.Server.Id);
var msg = new StringBuilder($"There are `{config.ListOfSelfAssignableRoles.Count}` self assignable roles:\n"); var msg = new StringBuilder($"There are `{config.ListOfSelfAssignableRoles.Count}` self assignable roles:\n");
var toRemove = new HashSet<ulong>(); 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); var role = e.Server.GetRole(roleId);
if (role == null) if (role == null)
@ -94,10 +94,23 @@ namespace NadekoBot.Modules.Administration.Commands
await e.Channel.SendMessage(msg.ToString()).ConfigureAwait(false); await e.Channel.SendMessage(msg.ToString()).ConfigureAwait(false);
}); });
cgb.CreateCommand(Module.Prefix + "togglexclsar").Alias(Module.Prefix +"tesar")
.Description("toggle whether the self-assigned roles should be exclusive")
.AddCheck(SimpleCheckers.CanManageRoles)
.Do(async e =>
{
var config = SpecificConfigurations.Default.Of(e.Server.Id);
config.ExclusiveSelfAssignedRoles = !config.ExclusiveSelfAssignedRoles;
string exl = config.ExclusiveSelfAssignedRoles ? "exclusive" : "not exclusive";
await e.Channel.SendMessage("Self assigned roles are now " + exl);
});
cgb.CreateCommand(Module.Prefix + "iam") cgb.CreateCommand(Module.Prefix + "iam")
.Description("Adds a role to you that you choose. " + .Description("Adds a role to you that you choose. " +
"Role must be on a list of self-assignable roles." + "Role must be on a list of self-assignable roles." +
"\n**Usage**: .iam Gamer") " | .iam Gamer")
.Parameter("role", ParameterType.Unparsed) .Parameter("role", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -121,6 +134,12 @@ namespace NadekoBot.Modules.Administration.Commands
await e.Channel.SendMessage($":anger:You already have {role.Name} role.").ConfigureAwait(false); await e.Channel.SendMessage($":anger:You already have {role.Name} role.").ConfigureAwait(false);
return; return;
} }
var sameRoles = e.User.Roles.Where(r => config.ListOfSelfAssignableRoles.Contains(r.Id));
if (config.ExclusiveSelfAssignedRoles && sameRoles.Any())
{
await e.Channel.SendMessage($":anger:You already have {sameRoles.FirstOrDefault().Name} role.").ConfigureAwait(false);
return;
}
try try
{ {
await e.User.AddRoles(role).ConfigureAwait(false); await e.User.AddRoles(role).ConfigureAwait(false);
@ -130,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); 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); var msg = await e.Channel.SendMessage($":ok:You now have {role.Name} role.").ConfigureAwait(false);
await Task.Delay(3000); await Task.Delay(3000).ConfigureAwait(false);
await msg.Delete(); await msg.Delete().ConfigureAwait(false);
try try
{ {
await e.Message.Delete().ConfigureAwait(false); await e.Message.Delete().ConfigureAwait(false);
@ -143,7 +162,7 @@ namespace NadekoBot.Modules.Administration.Commands
.Alias(Module.Prefix + "iamn") .Alias(Module.Prefix + "iamn")
.Description("Removes a role to you that you choose. " + .Description("Removes a role to you that you choose. " +
"Role must be on a list of self-assignable roles." + "Role must be on a list of self-assignable roles." +
"\n**Usage**: .iamn Gamer") " | .iamn Gamer")
.Parameter("role", ParameterType.Unparsed) .Parameter("role", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -168,7 +187,14 @@ namespace NadekoBot.Modules.Administration.Commands
return; return;
} }
await e.User.RemoveRoles(role).ConfigureAwait(false); 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) internal override void Init(CommandGroupBuilder cgb)
{ {
cgb.CreateCommand(Module.Prefix + "leave") 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) .Parameter("arg", ParameterType.Required)
.AddCheck(SimpleCheckers.OwnerOnly()) .AddCheck(SimpleCheckers.OwnerOnly())
.Do(async e => .Do(async e =>

View File

@ -245,7 +245,7 @@ namespace NadekoBot.Modules.Administration.Commands
}); });
cgb.CreateCommand(Module.Prefix + "greetmsg") 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) .Parameter("msg", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -278,7 +278,7 @@ namespace NadekoBot.Modules.Administration.Commands
}); });
cgb.CreateCommand(Module.Prefix + "byemsg") 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) .Parameter("msg", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {

View File

@ -36,7 +36,7 @@ namespace NadekoBot.Modules.Administration.Commands
internal override void Init(CommandGroupBuilder cgb) internal override void Init(CommandGroupBuilder cgb)
{ {
cgb.CreateCommand(Module.Prefix + "voicenotif") 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) .Parameter("voice_name", ParameterType.Unparsed)
.Do(DoFunc()); .Do(DoFunc());
} }

View File

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

View File

@ -7,6 +7,10 @@ using System.Threading.Tasks;
namespace NadekoBot.Classes.ClashOfClans namespace NadekoBot.Classes.ClashOfClans
{ {
public enum DestroyStars
{
One, Two, Three
}
internal class Caller internal class Caller
{ {
public string CallUser { get; } public string CallUser { get; }
@ -15,6 +19,9 @@ namespace NadekoBot.Classes.ClashOfClans
public bool BaseDestroyed { get; internal set; } public bool BaseDestroyed { get; internal set; }
public int Stars { get; set; } = 3;
public Caller(string callUser, DateTime timeAdded, bool baseDestroyed) public Caller(string callUser, DateTime timeAdded, bool baseDestroyed)
{ {
CallUser = callUser; CallUser = callUser;
@ -148,7 +155,7 @@ namespace NadekoBot.Classes.ClashOfClans
{ {
if (bases[i].BaseDestroyed) if (bases[i].BaseDestroyed)
{ {
sb.AppendLine($"`{i + 1}.` ✅ `{bases[i].CallUser}` ⭐ ⭐ ⭐"); sb.AppendLine($"`{i + 1}.` ✅ `{bases[i].CallUser}` {new string('⭐', bases[i].Stars)}");
} }
else else
{ {
@ -161,13 +168,14 @@ namespace NadekoBot.Classes.ClashOfClans
return sb.ToString(); return sb.ToString();
} }
internal int FinishClaim(string user) internal int FinishClaim(string user, int stars = 3)
{ {
user = user.Trim(); user = user.Trim();
for (var i = 0; i < bases.Length; i++) for (var i = 0; i < bases.Length; i++)
{ {
if (bases[i]?.BaseDestroyed != false || bases[i]?.CallUser != user) continue; if (bases[i]?.BaseDestroyed != false || bases[i]?.CallUser != user) continue;
bases[i].BaseDestroyed = true; bases[i].BaseDestroyed = true;
bases[i].Stars = stars;
return i; return i;
} }
throw new InvalidOperationException($"@{user} You are either not participating in that war, or you already destroyed a base."); 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.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
using System.Threading.Tasks;
using NadekoBot.Modules.Permissions.Classes;
namespace NadekoBot.Modules.ClashOfClans namespace NadekoBot.Modules.ClashOfClans
{ {
@ -21,10 +23,11 @@ namespace NadekoBot.Modules.ClashOfClans
manager.CreateCommands("", cgb => manager.CreateCommands("", cgb =>
{ {
cgb.CreateCommand(Prefix + "createwar") cgb.AddCheck(PermissionChecker.Instance);
cgb.CreateCommand(Prefix + "createwar")
.Alias(Prefix + "cw") .Alias(Prefix + "cw")
.Description( .Description($"Creates a new war by specifying a size (>10 and multiple of 5) and enemy clan name. |{Prefix}cw 15 The Enemy Clan")
$"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")
.Parameter("size") .Parameter("size")
.Parameter("enemy_clan", ParameterType.Unparsed) .Parameter("enemy_clan", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
@ -102,7 +105,7 @@ namespace NadekoBot.Modules.ClashOfClans
cgb.CreateCommand(Prefix + "listwar") cgb.CreateCommand(Prefix + "listwar")
.Alias(Prefix + "lw") .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) .Parameter("number", ParameterType.Optional)
.Do(async e => .Do(async e =>
{ {
@ -143,7 +146,7 @@ namespace NadekoBot.Modules.ClashOfClans
cgb.CreateCommand(Prefix + "claim") cgb.CreateCommand(Prefix + "claim")
.Alias(Prefix + "call") .Alias(Prefix + "call")
.Alias(Prefix + "c") .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("number")
.Parameter("baseNumber") .Parameter("baseNumber")
.Parameter("other_name", ParameterType.Unparsed) .Parameter("other_name", ParameterType.Unparsed)
@ -179,38 +182,31 @@ namespace NadekoBot.Modules.ClashOfClans
cgb.CreateCommand(Prefix + "claimfinish") cgb.CreateCommand(Prefix + "claimfinish")
.Alias(Prefix + "cf") .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("number", ParameterType.Required)
.Parameter("other_name", ParameterType.Unparsed) .Parameter("other_name", ParameterType.Unparsed)
.Do(async e => .Do(e => FinishClaim(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");
var war = warInfo.Item1[warInfo.Item2]; cgb.CreateCommand(Prefix + "claimfinish2")
try .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]")
var baseNum = war.FinishClaim(usr); .Parameter("number", ParameterType.Required)
await e.Channel.SendMessage($"❗🔰{e.User.Mention} **DESTROYED** a base #{baseNum + 1} in a war against {war.ShortPrint()}").ConfigureAwait(false); .Parameter("other_name", ParameterType.Unparsed)
} .Do(e => FinishClaim(e, 2));
catch (Exception ex)
{ cgb.CreateCommand(Prefix + "claimfinish1")
await e.Channel.SendMessage($"💢🔰 {ex.Message}").ConfigureAwait(false); .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") cgb.CreateCommand(Prefix + "unclaim")
.Alias(Prefix + "uncall") .Alias(Prefix + "uncall")
.Alias(Prefix + "uc") .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("number", ParameterType.Required)
.Parameter("other_name", ParameterType.Unparsed) .Parameter("other_name", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
@ -239,7 +235,7 @@ namespace NadekoBot.Modules.ClashOfClans
cgb.CreateCommand(Prefix + "endwar") cgb.CreateCommand(Prefix + "endwar")
.Alias(Prefix + "ew") .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") .Parameter("number")
.Do(async e => .Do(async e =>
{ {
@ -257,6 +253,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) private static Tuple<List<ClashWar>, int> GetInfo(CommandEventArgs e)
{ {
//check if there are any wars //check if there are any wars

View File

@ -23,7 +23,7 @@ namespace NadekoBot.Modules.Conversations.Commands
internal override void Init(CommandGroupBuilder cgb) internal override void Init(CommandGroupBuilder cgb)
{ {
cgb.CreateCommand("rip") 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("user", ParameterType.Required)
.Parameter("year", ParameterType.Optional) .Parameter("year", ParameterType.Optional)
.Do(async e => .Do(async e =>

View File

@ -32,7 +32,7 @@ namespace NadekoBot.Modules.Conversations
cgb.AddCheck(PermissionChecker.Instance); cgb.AddCheck(PermissionChecker.Instance);
cgb.CreateCommand("..") 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("keyword", ParameterType.Required)
.Parameter("text", ParameterType.Unparsed) .Parameter("text", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
@ -53,7 +53,7 @@ namespace NadekoBot.Modules.Conversations
}); });
cgb.CreateCommand("...") 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) .Parameter("keyword", ParameterType.Required)
.Do(async e => .Do(async e =>
{ {
@ -73,7 +73,7 @@ namespace NadekoBot.Modules.Conversations
cgb.CreateCommand("..qdel") cgb.CreateCommand("..qdel")
.Alias("..quotedelete") .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) .Parameter("quote", ParameterType.Required)
.Do(async e => .Do(async e =>
{ {
@ -100,15 +100,6 @@ namespace NadekoBot.Modules.Conversations
commands.ForEach(cmd => cmd.Init(cgb)); 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") cgb.CreateCommand("die")
.Description("Works only for the owner. Shuts the bot down.") .Description("Works only for the owner. Shuts the bot down.")
.Do(async e => .Do(async e =>
@ -158,7 +149,7 @@ namespace NadekoBot.Modules.Conversations
}); });
cgb.CreateCommand("fire") 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) .Parameter("times", ParameterType.Optional)
.Do(async e => .Do(async e =>
{ {
@ -180,38 +171,6 @@ namespace NadekoBot.Modules.Conversations
await e.Channel.SendMessage(str).ConfigureAwait(false); 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") cgb.CreateCommand("dump")
.Description("Dumps all of the invites it can to dump.txt.** Owner Only.**") .Description("Dumps all of the invites it can to dump.txt.** Owner Only.**")
.Do(async e => .Do(async e =>

View File

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

View File

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

View File

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

View File

@ -21,11 +21,18 @@ namespace NadekoBot.Modules.Gambling
{ {
cgb.CreateCommand(Module.Prefix + "roll") cgb.CreateCommand(Module.Prefix + "roll")
.Description("Rolls 0-100. If you supply a number [x] it rolls up to 30 normal dice." + .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) .Parameter("num", ParameterType.Optional)
.Do(RollFunc()); .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") 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) .Parameter("range", ParameterType.Required)
.Do(NRollFunc()); .Do(NRollFunc());
} }
@ -40,7 +47,7 @@ namespace NadekoBot.Modules.Gambling
Regex dndRegex = new Regex(@"(?<n1>\d+)d(?<n2>\d+)", RegexOptions.Compiled); 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(); var r = new Random();
return async e => return async e =>
@ -73,7 +80,7 @@ namespace NadekoBot.Modules.Gambling
arr[i] = r.Next(1, n2 + 1); arr[i] = r.Next(1, n2 + 1);
} }
var elemCnt = 0; 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; return;
} }
@ -92,17 +99,23 @@ namespace NadekoBot.Modules.Gambling
{ {
var randomNumber = r.Next(1, 7); var randomNumber = r.Next(1, 7);
var toInsert = dices.Count; var toInsert = dices.Count;
if (randomNumber == 6 || dices.Count == 0) if (ordered)
toInsert = 0; {
else if (randomNumber != 1) if (randomNumber == 6 || dices.Count == 0)
for (var j = 0; j < dices.Count; j++) toInsert = 0;
{ else if (randomNumber != 1)
if (values[j] < randomNumber) for (var j = 0; j < dices.Count; j++)
{ {
toInsert = j; if (values[j] < randomNumber)
break; {
toInsert = j;
break;
}
} }
} }
else {
toInsert = dices.Count;
}
dices.Insert(toInsert, GetDice(randomNumber)); dices.Insert(toInsert, GetDice(randomNumber));
values.Insert(toInsert, randomNumber); values.Insert(toInsert, randomNumber);
} }

View File

@ -17,7 +17,7 @@ namespace NadekoBot.Modules.Gambling
internal override void Init(CommandGroupBuilder cgb) internal override void Init(CommandGroupBuilder cgb)
{ {
cgb.CreateCommand(Module.Prefix + "draw") 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) .Parameter("count", ParameterType.Optional)
.Do(DrawCardFunc()); .Do(DrawCardFunc());

View File

@ -15,14 +15,68 @@ namespace NadekoBot.Modules.Gambling
internal override void Init(CommandGroupBuilder cgb) internal override void Init(CommandGroupBuilder cgb)
{ {
cgb.CreateCommand(Module.Prefix + "flip") 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) .Parameter("count", ParameterType.Optional)
.Do(FlipCoinFunc()); .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(); 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 => public Func<CommandEventArgs, Task> FlipCoinFunc() => async e =>
{ {

View File

@ -13,7 +13,6 @@ namespace NadekoBot.Modules.Gambling
{ {
internal class GamblingModule : DiscordModule internal class GamblingModule : DiscordModule
{ {
public GamblingModule() public GamblingModule()
{ {
commands.Add(new DrawCommand(this)); commands.Add(new DrawCommand(this));
@ -50,7 +49,7 @@ namespace NadekoBot.Modules.Gambling
}); });
cgb.CreateCommand(Prefix + "$$") 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)) NadekoBot.Config.CurrencyName, Prefix))
.Parameter("all", ParameterType.Unparsed) .Parameter("all", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
@ -69,7 +68,7 @@ namespace NadekoBot.Modules.Gambling
{ {
var amountStr = e.GetArg("amount")?.Trim(); var amountStr = e.GetArg("amount")?.Trim();
long amount; long amount;
if (!long.TryParse(amountStr, out amount) || amount < 0) if (!long.TryParse(amountStr, out amount) || amount <= 0)
return; return;
var mentionedUser = e.Message.MentionedUsers.FirstOrDefault(u => var mentionedUser = e.Message.MentionedUsers.FirstOrDefault(u =>
@ -82,11 +81,11 @@ namespace NadekoBot.Modules.Gambling
if (userFlowers < amount) 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; 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 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); 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") 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()) .AddCheck(SimpleCheckers.OwnerOnly())
.Parameter("amount", ParameterType.Required) .Parameter("amount", ParameterType.Required)
.Parameter("receiver", ParameterType.Unparsed) .Parameter("receiver", ParameterType.Unparsed)
@ -132,11 +131,58 @@ namespace NadekoBot.Modules.Gambling
if (mentionedUser == null) if (mentionedUser == null)
return; 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); 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") cgb.CreateCommand(Prefix + "leaderboard")
.Alias(Prefix + "lb") .Alias(Prefix + "lb")
.Do(async e => .Do(async e =>
@ -147,19 +193,19 @@ namespace NadekoBot.Modules.Gambling
return; return;
await e.Channel.SendMessage( await e.Channel.SendMessage(
richest.Aggregate(new StringBuilder( richest.Aggregate(new StringBuilder(
$@"```xl $@"```xl
Id $$$ Id $$$
"), "),
(cur, cs) => cur.AppendLine( (cur, cs) => cur.AppendLine(
$@"┣━━━━━━━━━━━━━━━━━━━╋━━━━━━━┫ $@"┣━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━┫
{cs.UserId,-18} {cs.Value,5} ") {(e.Server.Users.Where(u => u.Id == (ulong)cs.UserId).FirstOrDefault()?.Name.TrimTo(18, true) ?? cs.UserId.ToString()),-20} {cs.Value,5} ")
).ToString() + "┗━━━━━━━━━━━━━━━━━━━┻━━━━━━━┛```"); ).ToString() + "┗━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━┛```").ConfigureAwait(false);
}); });
}); });
} }
private static long GetUserFlowers(ulong userId) => public static long GetUserFlowers(ulong userId) =>
Classes.DbHandler.Instance.GetStateByUserId((long)userId)?.Value ?? 0; 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) internal override void Init(CommandGroupBuilder cgb)
{ {
cgb.CreateCommand(Module.Prefix + "leet") 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("level", ParameterType.Required)
.Parameter("text", ParameterType.Unparsed) .Parameter("text", ParameterType.Unparsed)
.Do(async e => .Do(async e =>

View File

@ -1,9 +1,11 @@
using Discord; using Discord;
using Discord.Commands; using Discord.Commands;
using NadekoBot.Classes; using NadekoBot.Classes;
using NadekoBot.Extensions;
using NadekoBot.Modules.Permissions.Classes; using NadekoBot.Modules.Permissions.Classes;
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Security.Cryptography; using System.Security.Cryptography;
@ -28,25 +30,34 @@ namespace NadekoBot.Modules.Games.Commands
rng = new Random(); rng = new Random();
} }
private static readonly ConcurrentDictionary<ulong, DateTime> plantpickCooldowns = new ConcurrentDictionary<ulong, DateTime>();
private async void PotentialFlowerGeneration(object sender, Discord.MessageEventArgs e) private async void PotentialFlowerGeneration(object sender, Discord.MessageEventArgs e)
{ {
if (e.Server == null || e.Channel.IsPrivate) try
return;
var config = Classes.SpecificConfigurations.Default.Of(e.Server.Id);
if (config.GenerateCurrencyChannels.Contains(e.Channel.Id))
{ {
var rnd = Math.Abs(GetRandomNumber()); if (e.Server == null || e.Channel.IsPrivate || e.Message.IsAuthor)
if ((rnd % 50) == 0) return;
{ var config = Classes.SpecificConfigurations.Default.Of(e.Server.Id);
var msg = await e.Channel.SendFile(GetRandomCurrencyImagePath()); var now = DateTime.Now;
await e.Channel.SendMessage($"❗ A random {NadekoBot.Config.CurrencyName} appeared! Pick it up by typing `>pick`"); int cd;
plantedFlowerChannels.AddOrUpdate(e.Channel.Id, msg, (u, m) => { m.Delete().GetAwaiter().GetResult(); return msg; }); 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(rng.Next(0,101));
if (rnd == 0)
{
var msgs = new[] { await e.Channel.SendFile(GetRandomCurrencyImagePath()), await e.Channel.SendMessage($"❗ A random {NadekoBot.Config.CurrencyName} appeared! Pick it up by typing `>pick`") };
plantedFlowerChannels.AddOrUpdate(e.Channel.Id, msgs, (u, m) => { m.ForEach(async msgToDelete => { try { await msgToDelete.Delete(); } catch { } }); return msgs; });
plantpickCooldowns.AddOrUpdate(e.Channel.Id, now, (i, d) => now);
}
}
} }
catch { }
} }
//channelid/messageid pair //channelid/messageid pair
ConcurrentDictionary<ulong, Message> plantedFlowerChannels = new ConcurrentDictionary<ulong, Message>(); ConcurrentDictionary<ulong, IEnumerable<Message>> plantedFlowerChannels = new ConcurrentDictionary<ulong, IEnumerable<Message>>();
private object locker = new object(); private object locker = new object();
@ -56,22 +67,24 @@ namespace NadekoBot.Modules.Games.Commands
.Description("Picks a flower planted in this channel.") .Description("Picks a flower planted in this channel.")
.Do(async e => .Do(async e =>
{ {
Message msg; IEnumerable<Message> msgs;
await e.Message.Delete().ConfigureAwait(false); await e.Message.Delete().ConfigureAwait(false);
if (!plantedFlowerChannels.TryRemove(e.Channel.Id, out msg)) if (!plantedFlowerChannels.TryRemove(e.Channel.Id, out msgs))
return; return;
await msg.Delete().ConfigureAwait(false); foreach(var msgToDelete in msgs)
await msgToDelete.Delete().ConfigureAwait(false);
await FlowersHandler.AddFlowersAsync(e.User, "Picked a flower.", 1, true).ConfigureAwait(false); await FlowersHandler.AddFlowersAsync(e.User, "Picked a flower.", 1, true).ConfigureAwait(false);
msg = await e.Channel.SendMessage($"**{e.User.Name}** picked a {NadekoBot.Config.CurrencyName}!").ConfigureAwait(false); var msg = await e.Channel.SendMessage($"**{e.User.Name}** picked a {NadekoBot.Config.CurrencyName}!").ConfigureAwait(false);
await Task.Delay(10000).ConfigureAwait(false); await Task.Delay(10000).ConfigureAwait(false);
await msg.Delete().ConfigureAwait(false); await msg.Delete().ConfigureAwait(false);
}); });
cgb.CreateCommand(Module.Prefix + "plant") cgb.CreateCommand(Module.Prefix + "plant")
.Description("Spend a flower to plant it in this channel. (If bot is restarted or crashes, flower will be lost)") .Description("Spend a flower to plant it in this channel. (If bot is restarted or crashes, flower will be lost)")
.Do(async e => .Do(e =>
{ {
lock (locker) lock (locker)
{ {
@ -80,7 +93,7 @@ namespace NadekoBot.Modules.Games.Commands
e.Channel.SendMessage($"There is already a {NadekoBot.Config.CurrencyName} in this channel."); e.Channel.SendMessage($"There is already a {NadekoBot.Config.CurrencyName} in this channel.");
return; return;
} }
var removed = FlowersHandler.RemoveFlowers(e.User, "Planted a flower.", 1); var removed = FlowersHandler.RemoveFlowers(e.User, "Planted a flower.", 1, true).GetAwaiter().GetResult();
if (!removed) if (!removed)
{ {
e.Channel.SendMessage($"You don't have any {NadekoBot.Config.CurrencyName}s.").Wait(); e.Channel.SendMessage($"You don't have any {NadekoBot.Config.CurrencyName}s.").Wait();
@ -94,29 +107,35 @@ namespace NadekoBot.Modules.Games.Commands
msg = e.Channel.SendMessage(NadekoBot.Config.CurrencySign).GetAwaiter().GetResult(); msg = e.Channel.SendMessage(NadekoBot.Config.CurrencySign).GetAwaiter().GetResult();
else else
msg = e.Channel.SendFile(file).GetAwaiter().GetResult(); msg = e.Channel.SendFile(file).GetAwaiter().GetResult();
plantedFlowerChannels.TryAdd(e.Channel.Id, msg); var vowelFirst = new[] { 'a', 'e', 'i', 'o', 'u' }.Contains(NadekoBot.Config.CurrencyName[0]);
var msg2 = e.Channel.SendMessage($"Oh how Nice! **{e.User.Name}** planted {(vowelFirst ? "an" : "a")} {NadekoBot.Config.CurrencyName}. Pick it using {Module.Prefix}pick").GetAwaiter().GetResult();
plantedFlowerChannels.TryAdd(e.Channel.Id, new[] { msg, msg2 });
} }
var vowelFirst = new[] { 'a', 'e', 'i', 'o', 'u' }.Contains(NadekoBot.Config.CurrencyName[0]);
var msg2 = await e.Channel.SendMessage($"Oh how Nice! **{e.User.Name}** planted {(vowelFirst ? "an" : "a")} {NadekoBot.Config.CurrencyName}. Pick it using {Module.Prefix}pick");
await Task.Delay(20000).ConfigureAwait(false);
await msg2.Delete().ConfigureAwait(false);
}); });
cgb.CreateCommand(Prefix + "gencurrency") cgb.CreateCommand(Prefix + "gencurrency")
.Alias(Prefix + "gc") .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()) .AddCheck(SimpleCheckers.ManageMessages())
.Parameter("cd", ParameterType.Unparsed)
.Do(async e => .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); 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.`"); await e.Channel.SendMessage("`Currency generation disabled on this channel.`");
} }
else else
{ {
config.GenerateCurrencyChannels.Add(e.Channel.Id); if (config.GenerateCurrencyChannels.TryAdd(e.Channel.Id, cd))
await e.Channel.SendMessage("`Currency generation enabled on this channel.`"); 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) internal override void Init(CommandGroupBuilder cgb)
{ {
cgb.CreateCommand(Module.Prefix + "poll") 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) .Parameter("allargs", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {

View File

@ -20,7 +20,7 @@ namespace NadekoBot.Modules.Games.Commands
cgb.CreateCommand(Module.Prefix + "t") cgb.CreateCommand(Module.Prefix + "t")
.Description($"Starts a game of trivia. You can add nohint to prevent hints." + .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." + "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) .Parameter("args", ParameterType.Multiple)
.Do(async e => .Do(async e =>
{ {

View File

@ -36,7 +36,7 @@ namespace NadekoBot.Modules.Games
commands.ForEach(cmd => cmd.Init(cgb)); commands.ForEach(cmd => cmd.Init(cgb));
cgb.CreateCommand(Prefix + "choose") 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) .Parameter("list", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -67,7 +67,7 @@ namespace NadekoBot.Modules.Games
}); });
cgb.CreateCommand(Prefix + "rps") 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) .Parameter("input", ParameterType.Required)
.Do(async e => .Do(async e =>
{ {
@ -107,7 +107,7 @@ namespace NadekoBot.Modules.Games
}); });
cgb.CreateCommand(Prefix + "linux") 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("gnu", ParameterType.Required)
.Parameter("linux", ParameterType.Required) .Parameter("linux", ParameterType.Required)
.Do(async e => .Do(async e =>

View File

@ -25,7 +25,7 @@ namespace NadekoBot.Classes.Help.Commands
.FirstOrDefault(c => c.Text.ToLowerInvariant().Equals(comToFind) || .FirstOrDefault(c => c.Text.ToLowerInvariant().Equals(comToFind) ||
c.Aliases.Select(a => a.ToLowerInvariant()).Contains(comToFind)); c.Aliases.Select(a => a.ToLowerInvariant()).Contains(comToFind));
if (com != null) 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); }).ConfigureAwait(false);
}; };
public static string HelpString { public static string HelpString {
@ -43,7 +43,7 @@ namespace NadekoBot.Classes.Help.Commands
{ {
string helpstr = string helpstr =
$@"######For more information and how to setup your own NadekoBot, go to: **http://github.com/Kwoth/NadekoBot/** $@"######For more information and how to setup your own NadekoBot, go to: **http://github.com/Kwoth/NadekoBot/**
######You can donate on paypal: `nadekodiscordbot@gmail.com` or Bitcoin `17MZz1JAqME39akMLrVT4XBPffQJ2n1EPa` ######You can donate on paypal: `nadekodiscordbot@gmail.com`
#NadekoBot List Of Commands #NadekoBot List Of Commands
Version: `{NadekoStats.Instance.BotVersion}`"; Version: `{NadekoStats.Instance.BotVersion}`";
@ -62,7 +62,7 @@ Version: `{NadekoStats.Instance.BotVersion}`";
helpstr += PrintCommandHelp(com); helpstr += PrintCommandHelp(com);
} }
helpstr = helpstr.Replace(NadekoBot.BotMention, "@BotName"); 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 #if DEBUG
File.WriteAllText("../../../commandlist.md", helpstr); File.WriteAllText("../../../commandlist.md", helpstr);
#else #else
@ -74,7 +74,7 @@ Version: `{NadekoStats.Instance.BotVersion}`";
{ {
cgb.CreateCommand(Module.Prefix + "h") cgb.CreateCommand(Module.Prefix + "h")
.Alias(Module.Prefix + "help", NadekoBot.BotMention + " help", NadekoBot.BotMention + " h", "~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) .Parameter("command", ParameterType.Unparsed)
.Do(HelpFunc()); .Do(HelpFunc());
cgb.CreateCommand(Module.Prefix + "hgit") cgb.CreateCommand(Module.Prefix + "hgit")

View File

@ -46,20 +46,25 @@ namespace NadekoBot.Modules.Help
if (string.IsNullOrWhiteSpace(module)) if (string.IsNullOrWhiteSpace(module))
return; return;
var cmds = NadekoBot.Client.GetService<CommandService>().AllCommands var cmds = NadekoBot.Client.GetService<CommandService>().AllCommands
.Where(c => c.Category.ToLower() == module); .Where(c => c.Category.ToLower() == module)
.OrderBy(c=>c.Text)
.AsEnumerable();
var cmdsArray = cmds as Command[] ?? cmds.ToArray(); var cmdsArray = cmds as Command[] ?? cmds.ToArray();
if (!cmdsArray.Any()) if (!cmdsArray.Any())
{ {
await e.Channel.SendMessage("That module does not exist.").ConfigureAwait(false); await e.Channel.SendMessage("That module does not exist.").ConfigureAwait(false);
return; return;
} }
var i = 0;
if (module != "customreactions" && module != "conversations") if (module != "customreactions" && module != "conversations")
{
await e.Channel.SendMessage("`List Of Commands:`\n" + SearchHelper.ShowInPrettyCode<Command>(cmdsArray, await e.Channel.SendMessage("`List Of Commands:`\n" + SearchHelper.ShowInPrettyCode<Command>(cmdsArray,
el => $"{el.Text,-15}{"[" + el.Aliases.FirstOrDefault() + "]",-8}")) el => $"{el.Text,-15}{"[" + el.Aliases.FirstOrDefault() + "]",-8}"))
.ConfigureAwait(false); .ConfigureAwait(false);
}
else else
{
await e.Channel.SendMessage("`List Of Commands:`\n• " + string.Join("\n• ", cmdsArray.Select(c => $"{c.Text}"))); 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); 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, Radio,
Normal, Normal,
Local Local,
Soundcloud
} }
public enum StreamState public enum StreamState
@ -51,6 +52,7 @@ namespace NadekoBot.Modules.Music.Classes
public bool RepeatSong { get; private set; } = false; public bool RepeatSong { get; private set; } = false;
public bool RepeatPlaylist { get; private set; } = false; public bool RepeatPlaylist { get; private set; } = false;
public bool Autoplay { get; set; } = false; public bool Autoplay { get; set; } = false;
public uint MaxQueueSize { get; set; } = 0;
public MusicPlayer(Channel startingVoiceChannel, float? defaultVolume) 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) if (s == null)
throw new ArgumentNullException(nameof(s)); throw new ArgumentNullException(nameof(s));
ThrowIfQueueFull();
lock (playlistLock) lock (playlistLock)
{ {
s.MusicPlayer = this; s.MusicPlayer = this;
s.QueuerName = username.TrimTo(10);
playlist.Add(s); playlist.Add(s);
} }
} }
@ -243,5 +247,13 @@ namespace NadekoBot.Modules.Music.Classes
internal bool ToggleRepeatPlaylist() => this.RepeatPlaylist = !this.RepeatPlaylist; internal bool ToggleRepeatPlaylist() => this.RepeatPlaylist = !this.RepeatPlaylist;
internal bool ToggleAutoplay() => this.Autoplay = !this.Autoplay; 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 StreamState State { get; internal set; }
public string PrettyName => public string PrettyName =>
$"**【 {SongInfo.Title.TrimTo(55)} 】**`{(SongInfo.Provider ?? "-")}`"; $"**【 {SongInfo.Title.TrimTo(55)} 】**`{(SongInfo.Provider ?? "-")}` `by {QueuerName}`";
public SongInfo SongInfo { get; } public SongInfo SongInfo { get; }
public string QueuerName { get; set; }
private PoopyBuffer songBuffer { get; } = new PoopyBuffer(NadekoBot.Config.BufferSize); private PoopyBuffer songBuffer { get; } = new PoopyBuffer(NadekoBot.Config.BufferSize);
@ -244,16 +245,30 @@ namespace NadekoBot.Modules.Music.Classes
} }
if (SoundCloud.Default.IsSoundCloudLink(query)) 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 return new Song(new SongInfo
{ {
Title = svideo.FullName, Title = svideo.FullName,
Provider = "SoundCloud", Provider = "SoundCloud",
Uri = svideo.StreamLink, Uri = svideo.StreamLink,
ProviderType = musicType, 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); var link = await SearchHelper.FindYoutubeUrlByKeywords(query).ConfigureAwait(false);
if (string.IsNullOrWhiteSpace(link)) if (string.IsNullOrWhiteSpace(link))
throw new OperationCanceledException("Not a valid youtube query."); throw new OperationCanceledException("Not a valid youtube query.");

View File

@ -1,6 +1,7 @@
using NadekoBot.Classes; using NadekoBot.Classes;
using Newtonsoft.Json; using Newtonsoft.Json;
using System; using System;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace NadekoBot.Modules.Music.Classes namespace NadekoBot.Modules.Music.Classes
@ -13,7 +14,7 @@ namespace NadekoBot.Modules.Music.Classes
static SoundCloud() { } static SoundCloud() { }
public SoundCloud() { } public SoundCloud() { }
public async Task<SoundCloudVideo> GetVideoAsync(string url) public async Task<SoundCloudVideo> ResolveVideoAsync(string url)
{ {
if (string.IsNullOrWhiteSpace(url)) if (string.IsNullOrWhiteSpace(url))
throw new ArgumentNullException(nameof(url)); throw new ArgumentNullException(nameof(url));
@ -31,6 +32,22 @@ namespace NadekoBot.Modules.Music.Classes
public bool IsSoundCloudLink(string url) => public bool IsSoundCloudLink(string url) =>
System.Text.RegularExpressions.Regex.IsMatch(url, "(.*)(soundcloud.com|snd.sc)(.*)"); 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 public class SoundCloudVideo

View File

@ -31,17 +31,17 @@ namespace NadekoBot.Modules.Music
{ {
var client = NadekoBot.Client; var client = NadekoBot.Client;
manager.CreateCommands(Prefix, cgb => manager.CreateCommands("", cgb =>
{ {
cgb.AddCheck(PermissionChecker.Instance); cgb.AddCheck(PermissionChecker.Instance);
commands.ForEach(cmd => cmd.Init(cgb)); commands.ForEach(cmd => cmd.Init(cgb));
cgb.CreateCommand("next") cgb.CreateCommand(Prefix + "next")
.Alias("n") .Alias(Prefix + "n")
.Alias("skip") .Alias(Prefix + "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 => .Do(e =>
{ {
MusicPlayer musicPlayer; MusicPlayer musicPlayer;
@ -50,9 +50,9 @@ namespace NadekoBot.Modules.Music
musicPlayer.Next(); musicPlayer.Next();
}); });
cgb.CreateCommand("stop") cgb.CreateCommand(Prefix + "stop")
.Alias("s") .Alias(Prefix + "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 => .Do(e =>
{ {
MusicPlayer musicPlayer; MusicPlayer musicPlayer;
@ -64,10 +64,10 @@ namespace NadekoBot.Modules.Music
} }
}); });
cgb.CreateCommand("destroy") cgb.CreateCommand(Prefix + "destroy")
.Alias("d") .Alias(Prefix + "d")
.Description("Completely stops the music and unbinds the bot from the channel. " + .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 => .Do(e =>
{ {
MusicPlayer musicPlayer; MusicPlayer musicPlayer;
@ -76,9 +76,9 @@ namespace NadekoBot.Modules.Music
musicPlayer.Destroy(); musicPlayer.Destroy();
}); });
cgb.CreateCommand("pause") cgb.CreateCommand(Prefix + "pause")
.Alias("p") .Alias(Prefix + "p")
.Description("Pauses or Unpauses the song.\n**Usage**: `!m p`") .Description("Pauses or Unpauses the song. | `!m p`")
.Do(async e => .Do(async e =>
{ {
MusicPlayer musicPlayer; MusicPlayer musicPlayer;
@ -92,15 +92,15 @@ namespace NadekoBot.Modules.Music
await e.Channel.SendMessage("🎵`Music Player unpaused.`").ConfigureAwait(false); await e.Channel.SendMessage("🎵`Music Player unpaused.`").ConfigureAwait(false);
}); });
cgb.CreateCommand("queue") cgb.CreateCommand(Prefix + "queue")
.Alias("q") .Alias(Prefix + "q")
.Alias("yq") .Alias(Prefix + "yq")
.Description("Queue a song using keywords or a link. Bot will join your voice channel." + .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) .Parameter("query", ParameterType.Unparsed)
.Do(async e => .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) if (e.Server.CurrentUser.GetPermissions(e.Channel).ManageMessages)
{ {
await Task.Delay(10000).ConfigureAwait(false); await Task.Delay(10000).ConfigureAwait(false);
@ -108,24 +108,24 @@ namespace NadekoBot.Modules.Music
} }
}); });
//cgb.CreateCommand("soundcloudqueue") cgb.CreateCommand(Prefix + "soundcloudqueue")
// .Alias("sq") .Alias(Prefix + "sq")
// .Description("Queue a soundcloud song using keywords. Bot will join your voice channel." + .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`") "**You must be in a voice channel**. | `!m sq Dream Of Venice`")
// .Parameter("query", ParameterType.Unparsed) .Parameter("query", ParameterType.Unparsed)
// .Do(async e => .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"), musicType: MusicType.Soundcloud).ConfigureAwait(false);
// if (e.Server.CurrentUser.GetPermissions(e.Channel).ManageMessages) if (e.Server.CurrentUser.GetPermissions(e.Channel).ManageMessages)
// { {
// await Task.Delay(10000).ConfigureAwait(false); await Task.Delay(10000).ConfigureAwait(false);
// await e.Message.Delete().ConfigureAwait(false); await e.Message.Delete().ConfigureAwait(false);
// } }
// }); });
cgb.CreateCommand("listqueue") cgb.CreateCommand(Prefix + "listqueue")
.Alias("lq") .Alias(Prefix + "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) .Parameter("page", ParameterType.Optional)
.Do(async e => .Do(async e =>
{ {
@ -161,9 +161,9 @@ namespace NadekoBot.Modules.Music
await e.Channel.SendMessage(toSend + string.Join("\n", musicPlayer.Playlist.Skip(startAt).Take(15).Select(v => $"`{number++}.` {v.PrettyName}"))).ConfigureAwait(false); await e.Channel.SendMessage(toSend + string.Join("\n", musicPlayer.Playlist.Skip(startAt).Take(15).Select(v => $"`{number++}.` {v.PrettyName}"))).ConfigureAwait(false);
}); });
cgb.CreateCommand("nowplaying") cgb.CreateCommand(Prefix + "nowplaying")
.Alias("np") .Alias(Prefix + "np")
.Description("Shows the song currently playing.\n**Usage**: `!m np`") .Description("Shows the song currently playing. | `!m np`")
.Do(async e => .Do(async e =>
{ {
MusicPlayer musicPlayer; MusicPlayer musicPlayer;
@ -176,9 +176,9 @@ namespace NadekoBot.Modules.Music
$"{currentSong.PrettyCurrentTime()}").ConfigureAwait(false); $"{currentSong.PrettyCurrentTime()}").ConfigureAwait(false);
}); });
cgb.CreateCommand("volume") cgb.CreateCommand(Prefix + "volume")
.Alias("vol") .Alias(Prefix + "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) .Parameter("val", ParameterType.Required)
.Do(async e => .Do(async e =>
{ {
@ -198,10 +198,10 @@ namespace NadekoBot.Modules.Music
await e.Channel.SendMessage($"🎵 `Volume set to {volume}%`").ConfigureAwait(false); await e.Channel.SendMessage($"🎵 `Volume set to {volume}%`").ConfigureAwait(false);
}); });
cgb.CreateCommand("defvol") cgb.CreateCommand(Prefix + "defvol")
.Alias("dv") .Alias(Prefix + "dv")
.Description("Sets the default music volume when music playback is started (0-100)." + .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) .Parameter("val", ParameterType.Required)
.Do(async e => .Do(async e =>
{ {
@ -217,8 +217,9 @@ namespace NadekoBot.Modules.Music
await e.Channel.SendMessage($"🎵 `Default volume set to {volume}%`").ConfigureAwait(false); await e.Channel.SendMessage($"🎵 `Default volume set to {volume}%`").ConfigureAwait(false);
}); });
cgb.CreateCommand("mute").Alias("min") cgb.CreateCommand(Prefix + "mute")
.Description("Sets the music volume to 0%\n**Usage**: `!m min`") .Alias(Prefix + "min")
.Description("Sets the music volume to 0% | `!m min`")
.Do(e => .Do(e =>
{ {
MusicPlayer musicPlayer; MusicPlayer musicPlayer;
@ -229,8 +230,8 @@ namespace NadekoBot.Modules.Music
musicPlayer.SetVolume(0); musicPlayer.SetVolume(0);
}); });
cgb.CreateCommand("max") cgb.CreateCommand(Prefix + "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 => .Do(e =>
{ {
MusicPlayer musicPlayer; MusicPlayer musicPlayer;
@ -241,8 +242,8 @@ namespace NadekoBot.Modules.Music
musicPlayer.SetVolume(100); musicPlayer.SetVolume(100);
}); });
cgb.CreateCommand("half") cgb.CreateCommand(Prefix + "half")
.Description("Sets the music volume to 50%.\n**Usage**: `!m half`") .Description("Sets the music volume to 50%. | `!m half`")
.Do(e => .Do(e =>
{ {
MusicPlayer musicPlayer; MusicPlayer musicPlayer;
@ -253,9 +254,9 @@ namespace NadekoBot.Modules.Music
musicPlayer.SetVolume(50); musicPlayer.SetVolume(50);
}); });
cgb.CreateCommand("shuffle") cgb.CreateCommand(Prefix + "shuffle")
.Alias("sh") .Alias(Prefix + "sh")
.Description("Shuffles the current playlist.\n**Usage**: `!m sh`") .Description("Shuffles the current playlist. | `!m sh`")
.Do(async e => .Do(async e =>
{ {
MusicPlayer musicPlayer; MusicPlayer musicPlayer;
@ -273,9 +274,9 @@ namespace NadekoBot.Modules.Music
await e.Channel.SendMessage("🎵 `Songs shuffled.`").ConfigureAwait(false); await e.Channel.SendMessage("🎵 `Songs shuffled.`").ConfigureAwait(false);
}); });
cgb.CreateCommand("playlist") cgb.CreateCommand(Prefix + "playlist")
.Alias("pl") .Alias(Prefix + "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) .Parameter("playlist", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -296,7 +297,7 @@ namespace NadekoBot.Modules.Music
var ids = await SearchHelper.GetVideoIDs(plId, 500).ConfigureAwait(false); var ids = await SearchHelper.GetVideoIDs(plId, 500).ConfigureAwait(false);
if (ids == null || ids.Count == 0) 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; return;
} }
//todo TEMPORARY SOLUTION, USE RESOLVE QUEUE IN THE FUTURE //todo TEMPORARY SOLUTION, USE RESOLVE QUEUE IN THE FUTURE
@ -308,15 +309,17 @@ namespace NadekoBot.Modules.Music
{ {
try 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 { } catch { }
} }
await msg.Edit("🎵 `Playlist queue complete.`").ConfigureAwait(false); await msg.Edit("🎵 `Playlist queue complete.`").ConfigureAwait(false);
}); });
cgb.CreateCommand("soundcloudpl") cgb.CreateCommand(Prefix + "soundcloudpl")
.Alias("scpl") .Alias(Prefix + "scpl")
.Description("Queue a soundcloud playlist using a link. | `!m scpl https://soundcloud.com/saratology/sets/symphony`") .Description("Queue a soundcloud playlist using a link. | `!m scpl https://soundcloud.com/saratology/sets/symphony`")
.Parameter("pl", ParameterType.Unparsed) .Parameter("pl", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
@ -326,8 +329,8 @@ namespace NadekoBot.Modules.Music
if (string.IsNullOrWhiteSpace(pl)) if (string.IsNullOrWhiteSpace(pl))
return; return;
var scvids = JObject.Parse(await SearchHelper.GetResponseStringAsync($"http://api.soundcloud.com/resolve?url={pl}&client_id={NadekoBot.Creds.SoundCloudClientID}"))["tracks"].ToObject<SoundCloudVideo[]>(); 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.Channel, e.User.VoiceChannel, scvids[0].TrackLink); await QueueSong(e.User, e.Channel, e.User.VoiceChannel, scvids[0].TrackLink).ConfigureAwait(false);
MusicPlayer mp; MusicPlayer mp;
if (!MusicPlayers.TryGetValue(e.Server, out mp)) if (!MusicPlayers.TryGetValue(e.Server, out mp))
@ -335,20 +338,24 @@ namespace NadekoBot.Modules.Music
foreach (var svideo in scvids.Skip(1)) foreach (var svideo in scvids.Skip(1))
{ {
mp.AddSong(new Song(new Classes.SongInfo try
{ {
Title = svideo.FullName, mp.AddSong(new Song(new Classes.SongInfo
Provider = "SoundCloud", {
Uri = svideo.StreamLink, Title = svideo.FullName,
ProviderType = MusicType.Normal, Provider = "SoundCloud",
Query = svideo.TrackLink, Uri = svideo.StreamLink,
})); ProviderType = MusicType.Normal,
Query = svideo.TrackLink,
}), e.User.Name);
}
catch (PlaylistFullException) { break; }
} }
}); });
cgb.CreateCommand("localplaylst") cgb.CreateCommand(Prefix + "localplaylst")
.Alias("lopl") .Alias(Prefix + "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) .Parameter("directory", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.OwnerOnly()) .AddCheck(SimpleCheckers.OwnerOnly())
.Do(async e => .Do(async e =>
@ -362,15 +369,23 @@ namespace NadekoBot.Modules.Music
.Where(x => !x.Attributes.HasFlag(FileAttributes.Hidden | FileAttributes.System)); .Where(x => !x.Attributes.HasFlag(FileAttributes.Hidden | FileAttributes.System));
foreach (var file in fileEnum) 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); await e.Channel.SendMessage("🎵 `Directory queue complete.`").ConfigureAwait(false);
} }
catch { } catch { }
}); });
cgb.CreateCommand("radio").Alias("ra") cgb.CreateCommand(Prefix + "radio").Alias(Prefix + "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) .Parameter("radio_link", ParameterType.Required)
.Do(async e => .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); 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; 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) if (e.Server.CurrentUser.GetPermissions(e.Channel).ManageMessages)
{ {
await Task.Delay(10000).ConfigureAwait(false); await Task.Delay(10000).ConfigureAwait(false);
@ -387,9 +402,9 @@ namespace NadekoBot.Modules.Music
} }
}); });
cgb.CreateCommand("local") cgb.CreateCommand(Prefix + "local")
.Alias("lo") .Alias(Prefix + "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) .Parameter("path", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.OwnerOnly()) .AddCheck(SimpleCheckers.OwnerOnly())
.Do(async e => .Do(async e =>
@ -397,12 +412,12 @@ namespace NadekoBot.Modules.Music
var arg = e.GetArg("path"); var arg = e.GetArg("path");
if (string.IsNullOrWhiteSpace(arg)) if (string.IsNullOrWhiteSpace(arg))
return; 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") cgb.CreateCommand(Prefix + "move")
.Alias("mv") .Alias(Prefix + "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 => .Do(e =>
{ {
MusicPlayer musicPlayer; MusicPlayer musicPlayer;
@ -412,9 +427,9 @@ namespace NadekoBot.Modules.Music
musicPlayer.MoveToVoiceChannel(voiceChannel); musicPlayer.MoveToVoiceChannel(voiceChannel);
}); });
cgb.CreateCommand("remove") cgb.CreateCommand(Prefix + "remove")
.Alias("rm") .Alias(Prefix + "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) .Parameter("num", ParameterType.Required)
.Do(async e => .Do(async e =>
{ {
@ -445,9 +460,9 @@ namespace NadekoBot.Modules.Music
}); });
//var msRegex = new Regex(@"(?<n1>\d+)>(?<n2>\d+)", RegexOptions.Compiled); //var msRegex = new Regex(@"(?<n1>\d+)>(?<n2>\d+)", RegexOptions.Compiled);
cgb.CreateCommand("movesong") cgb.CreateCommand(Prefix + "movesong")
.Alias("ms") .Alias(Prefix + "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") .Parameter("fromto")
.Do(async e => .Do(async e =>
{ {
@ -468,7 +483,7 @@ namespace NadekoBot.Modules.Music
!int.TryParse(fromtoArr[1], out n2) || n1 < 1 || n2 < 1 || n1 == n2 || !int.TryParse(fromtoArr[1], out n2) || n1 < 1 || n2 < 1 || n1 == n2 ||
n1 > playlist.Count || n2 > playlist.Count) n1 > playlist.Count || n2 > playlist.Count)
{ {
await e.Channel.SendMessage("`Invalid input.`"); await e.Channel.SendMessage("`Invalid input.`").ConfigureAwait(false);
return; return;
} }
@ -477,12 +492,35 @@ namespace NadekoBot.Modules.Music
var nn1 = n2 < n1 ? n1 : n1 - 1; var nn1 = n2 < n1 ? n1 : n1 - 1;
playlist.RemoveAt(nn1); 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("cleanup") cgb.CreateCommand(Prefix + "setmaxqueue")
.Description("Cleans up hanging voice connections. **Bot Owner Only!**\n**Usage**: `!m cleanup`") .Alias(Prefix + "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(Prefix + "cleanup")
.Description("Cleans up hanging voice connections. **Bot Owner Only!** | `!m cleanup`")
.AddCheck(SimpleCheckers.OwnerOnly()) .AddCheck(SimpleCheckers.OwnerOnly())
.Do(e => .Do(e =>
{ {
@ -499,9 +537,9 @@ namespace NadekoBot.Modules.Music
} }
}); });
cgb.CreateCommand("reptcursong") cgb.CreateCommand(Prefix + "reptcursong")
.Alias("rcs") .Alias(Prefix + "rcs")
.Description("Toggles repeat of current song.\n**Usage**: `!m rcs`") .Description("Toggles repeat of current song. | `!m rcs`")
.Do(async e => .Do(async e =>
{ {
MusicPlayer musicPlayer; MusicPlayer musicPlayer;
@ -517,9 +555,9 @@ namespace NadekoBot.Modules.Music
.ConfigureAwait(false); .ConfigureAwait(false);
}); });
cgb.CreateCommand("rpeatplaylst") cgb.CreateCommand(Prefix + "rpeatplaylst")
.Alias("rpl") .Alias(Prefix + "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 => .Do(async e =>
{ {
MusicPlayer musicPlayer; MusicPlayer musicPlayer;
@ -529,8 +567,8 @@ namespace NadekoBot.Modules.Music
await e.Channel.SendMessage($"🎵🔁`Repeat playlist {(currentValue ? "enabled" : "disabled")}`").ConfigureAwait(false); await e.Channel.SendMessage($"🎵🔁`Repeat playlist {(currentValue ? "enabled" : "disabled")}`").ConfigureAwait(false);
}); });
cgb.CreateCommand("save") cgb.CreateCommand(Prefix + "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) .Parameter("name", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -582,8 +620,8 @@ namespace NadekoBot.Modules.Music
}); });
cgb.CreateCommand("load") cgb.CreateCommand(Prefix + "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) .Parameter("name", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -628,7 +666,11 @@ namespace NadekoBot.Modules.Music
{ {
try 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) catch (Exception ex)
{ {
@ -637,9 +679,9 @@ namespace NadekoBot.Modules.Music
} }
}); });
cgb.CreateCommand("playlists") cgb.CreateCommand(Prefix + "playlists")
.Alias("pls") .Alias(Prefix + "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) .Parameter("num", ParameterType.Optional)
.Do(e => .Do(e =>
{ {
@ -649,13 +691,13 @@ namespace NadekoBot.Modules.Music
return; return;
var result = DbHandler.Instance.GetPlaylistData(num); var result = DbHandler.Instance.GetPlaylistData(num);
if (result.Count == 0) 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 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") cgb.CreateCommand(Prefix + "deleteplaylist")
.Alias("delpls") .Alias(Prefix + "delpls")
.Description("Deletes a saved playlist. Only if you made it or if you are the bot owner. | `!m delpls animu-5`") .Description("Deletes a saved playlist. Only if you made it or if you are the bot owner. | `!m delpls animu-5`")
.Parameter("pl", ParameterType.Required) .Parameter("pl", ParameterType.Required)
.Do(async e => .Do(async e =>
@ -668,10 +710,10 @@ namespace NadekoBot.Modules.Music
DbHandler.Instance.Delete<MusicPlaylist>(plnum); DbHandler.Instance.Delete<MusicPlaylist>(plnum);
else else
DbHandler.Instance.DeleteWhere<MusicPlaylist>(mp => mp.Id == plnum && (long)e.User.Id == mp.CreatorId); 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") cgb.CreateCommand(Prefix + "goto")
.Description("Goes to a specific time in seconds in a song.") .Description("Goes to a specific time in seconds in a song.")
.Parameter("time") .Parameter("time")
.Do(async e => .Do(async e =>
@ -708,8 +750,8 @@ namespace NadekoBot.Modules.Music
await e.Channel.SendMessage($"`Skipped to {minutes}:{seconds}`").ConfigureAwait(false); await e.Channel.SendMessage($"`Skipped to {minutes}:{seconds}`").ConfigureAwait(false);
}); });
cgb.CreateCommand("getlink") cgb.CreateCommand(Prefix + "getlink")
.Alias("gl") .Alias(Prefix + "gl")
.Description("Shows a link to the currently playing song.") .Description("Shows a link to the currently playing song.")
.Do(async e => .Do(async e =>
{ {
@ -719,11 +761,11 @@ namespace NadekoBot.Modules.Music
var curSong = musicPlayer.CurrentSong; var curSong = musicPlayer.CurrentSong;
if (curSong == null) if (curSong == null)
return; return;
await e.Channel.SendMessage($"🎶`Current song:` <{curSong.SongInfo.Query}>"); await e.Channel.SendMessage($"🎶`Current song:` <{curSong.SongInfo.Query}>").ConfigureAwait(false);
}); });
cgb.CreateCommand("autoplay") cgb.CreateCommand(Prefix + "autoplay")
.Alias("ap") .Alias(Prefix + "ap")
.Description("Toggles autoplay - When the song is finished, automatically queue a related youtube song. (Works only for youtube songs and when queue is empty)") .Description("Toggles autoplay - When the song is finished, automatically queue a related youtube song. (Works only for youtube songs and when queue is empty)")
.Do(async e => .Do(async e =>
{ {
@ -733,14 +775,14 @@ namespace NadekoBot.Modules.Music
return; return;
if (!musicPlayer.ToggleAutoplay()) if (!musicPlayer.ToggleAutoplay())
await e.Channel.SendMessage("🎶`Autoplay disabled.`"); await e.Channel.SendMessage("🎶`Autoplay disabled.`").ConfigureAwait(false);
else 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) if (voiceCh == null || voiceCh.Server != textCh.Server)
{ {
@ -772,7 +814,7 @@ namespace NadekoBot.Modules.Music
lastFinishedMessage = await textCh.SendMessage($"🎵`Finished`{song.PrettyName}").ConfigureAwait(false); lastFinishedMessage = await textCh.SendMessage($"🎵`Finished`{song.PrettyName}").ConfigureAwait(false);
if (mp.Autoplay && mp.Playlist.Count == 0 && song.SongInfo.Provider == "YouTube") 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) catch (Exception e)
@ -800,8 +842,19 @@ namespace NadekoBot.Modules.Music
}; };
return mp; return mp;
}); });
var resolvedSong = await Song.ResolveSong(query, musicType).ConfigureAwait(false); Song resolvedSong;
musicPlayer.AddSong(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) if (!silent)
{ {
var queuedMessage = await textCh.SendMessage($"🎵`Queued`{resolvedSong.PrettyName} **at** `#{musicPlayer.Playlist.Count}`").ConfigureAwait(false); 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.AddCheck(PermissionChecker.Instance);
cgb.CreateCommand(Prefix + "hentai") 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) .Parameter("tag", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -39,7 +39,7 @@ namespace NadekoBot.Modules.NSFW
await e.Channel.SendMessage("`No results.`"); await e.Channel.SendMessage("`No results.`");
}); });
cgb.CreateCommand(Prefix + "danbooru") 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) .Parameter("tag", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -51,7 +51,7 @@ namespace NadekoBot.Modules.NSFW
await e.Channel.SendMessage(link).ConfigureAwait(false); await e.Channel.SendMessage(link).ConfigureAwait(false);
}); });
cgb.CreateCommand(Prefix + "gelbooru") 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) .Parameter("tag", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -64,7 +64,7 @@ namespace NadekoBot.Modules.NSFW
}); });
cgb.CreateCommand(Prefix + "rule34") 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) .Parameter("tag", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -76,7 +76,7 @@ namespace NadekoBot.Modules.NSFW
await e.Channel.SendMessage(link).ConfigureAwait(false); await e.Channel.SendMessage(link).ConfigureAwait(false);
}); });
cgb.CreateCommand(Prefix + "e621") 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) .Parameter("tag", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {

View File

@ -4,6 +4,7 @@ using Discord.Commands.Permissions;
using NadekoBot.Classes.JSONModels; using NadekoBot.Classes.JSONModels;
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace NadekoBot.Modules.Permissions.Classes namespace NadekoBot.Modules.Permissions.Classes
@ -13,7 +14,10 @@ namespace NadekoBot.Modules.Permissions.Classes
{ {
public static PermissionChecker Instance { get; } = new PermissionChecker(); public static PermissionChecker Instance { get; } = new PermissionChecker();
private ConcurrentDictionary<User, DateTime> timeBlackList { get; } = new ConcurrentDictionary<User, DateTime>(); //key - sid:command
//value - userid
private ConcurrentDictionary<string, ulong> commandCooldowns = new ConcurrentDictionary<string, ulong>();
private HashSet<ulong> timeBlackList { get; } = new HashSet<ulong>();
static PermissionChecker() { } static PermissionChecker() { }
private PermissionChecker() private PermissionChecker()
@ -46,18 +50,26 @@ namespace NadekoBot.Modules.Permissions.Classes
return false; return false;
} }
if (timeBlackList.ContainsKey(user)) if (timeBlackList.Contains(user.Id))
return false; return false;
timeBlackList.TryAdd(user, DateTime.Now);
if (!channel.IsPrivate && !channel.Server.CurrentUser.GetPermissions(channel).SendMessages) if (!channel.IsPrivate && !channel.Server.CurrentUser.GetPermissions(channel).SendMessages)
{ {
return false; return false;
} }
//{
// user.SendMessage($"I ignored your command in {channel.Server.Name}/#{channel.Name} because i don't have permissions to write to it. Please use `;acm channel_name 0` in that server instead of muting me.").GetAwaiter().GetResult(); timeBlackList.Add(user.Id);
//}
ServerPermissions perms;
PermissionsHandler.PermissionsDict.TryGetValue(user.Server.Id, out perms);
AddUserCooldown(user.Server.Id, user.Id, command.Text.ToLower());
if (commandCooldowns.Keys.Contains(user.Server.Id+":"+command.Text.ToLower()))
{
if(perms?.Verbose == true)
error = $"{user.Mention} You have a cooldown on that command.";
return false;
}
try try
{ {
@ -75,8 +87,6 @@ namespace NadekoBot.Modules.Permissions.Classes
catch { } catch { }
if (user.Server.Owner.Id == user.Id || (role != null && user.HasRole(role))) if (user.Server.Owner.Id == user.Id || (role != null && user.HasRole(role)))
return true; return true;
ServerPermissions perms;
PermissionsHandler.PermissionsDict.TryGetValue(user.Server.Id, out perms);
throw new Exception($"You don't have the necessary role (**{(perms?.PermissionsControllerRole ?? "Nadeko")}**) to change permissions."); throw new Exception($"You don't have the necessary role (**{(perms?.PermissionsControllerRole ?? "Nadeko")}**) to change permissions.");
} }
@ -128,8 +138,7 @@ namespace NadekoBot.Modules.Permissions.Classes
Console.WriteLine($"Exception in canrun: {ex}"); Console.WriteLine($"Exception in canrun: {ex}");
try try
{ {
ServerPermissions perms; if (perms != null && perms.Verbose)
if (PermissionsHandler.PermissionsDict.TryGetValue(user.Server.Id, out perms) && perms.Verbose)
//if verbose - print errors //if verbose - print errors
error = ex.Message; error = ex.Message;
} }
@ -140,5 +149,26 @@ namespace NadekoBot.Modules.Permissions.Classes
return false; return false;
} }
} }
public void AddUserCooldown(ulong serverId, ulong userId, string commandName) {
commandCooldowns.TryAdd(commandName, userId);
var tosave = serverId + ":" + commandName;
Task.Run(async () =>
{
ServerPermissions perms;
PermissionsHandler.PermissionsDict.TryGetValue(serverId, out perms);
int cd;
if (!perms.CommandCooldowns.TryGetValue(commandName,out cd)) {
return;
}
if (commandCooldowns.TryAdd(tosave, userId))
{
await Task.Delay(cd * 1000);
ulong throwaway;
commandCooldowns.TryRemove(tosave, out throwaway);
}
});
}
} }
} }

View File

@ -55,9 +55,11 @@ namespace NadekoBot.Modules.Permissions.Classes
if (string.IsNullOrWhiteSpace(commandText)) if (string.IsNullOrWhiteSpace(commandText))
throw new ArgumentNullException(nameof(commandText)); throw new ArgumentNullException(nameof(commandText));
var normalizedCmdTxt = commandText.Trim().ToUpperInvariant();
foreach (var com in NadekoBot.Client.GetService<CommandService>().AllCommands) foreach (var com in NadekoBot.Client.GetService<CommandService>().AllCommands)
{ {
if (com.Text.ToLower().Equals(commandText.Trim().ToLower())) if (com.Text.ToUpperInvariant().Equals(normalizedCmdTxt) || com.Aliases.Select(c=>c.ToUpperInvariant()).Contains(normalizedCmdTxt))
return com.Text; return com.Text;
} }
throw new NullReferenceException("That command does not exist."); throw new NullReferenceException("That command does not exist.");

View File

@ -424,6 +424,21 @@ namespace NadekoBot.Modules.Permissions.Classes
Task.Run(() => WriteServerToJson(serverPerms)); Task.Run(() => WriteServerToJson(serverPerms));
} }
public static void SetCommandCooldown(Server server, string commandName, int value)
{
var serverPerms = PermissionsDict.GetOrAdd(server.Id,
new ServerPermissions(server.Id, server.Name));
if (value == 0) {
int throwaway;
serverPerms.CommandCooldowns.TryRemove(commandName, out throwaway);
}
else {
serverPerms.CommandCooldowns.AddOrUpdate(commandName, value, (str, v) => value);
}
Task.Run(() => WriteServerToJson(serverPerms));
}
public static void AddFilteredWord(Server server, string word) public static void AddFilteredWord(Server server, string word)
{ {
var serverPerms = PermissionsDict.GetOrAdd(server.Id, var serverPerms = PermissionsDict.GetOrAdd(server.Id,
@ -537,6 +552,10 @@ namespace NadekoBot.Modules.Permissions.Classes
public Dictionary<ulong, Permissions> UserPermissions { get; set; } public Dictionary<ulong, Permissions> UserPermissions { get; set; }
public Dictionary<ulong, Permissions> ChannelPermissions { get; set; } public Dictionary<ulong, Permissions> ChannelPermissions { get; set; }
public Dictionary<ulong, Permissions> RolePermissions { get; set; } public Dictionary<ulong, Permissions> RolePermissions { get; set; }
/// <summary>
/// Dictionary of command names with their respective cooldowns
/// </summary>
public ConcurrentDictionary<string, int> CommandCooldowns { get; set; }
public ServerPermissions(ulong id, string name) public ServerPermissions(ulong id, string name)
{ {
@ -549,6 +568,7 @@ namespace NadekoBot.Modules.Permissions.Classes
UserPermissions = new Dictionary<ulong, Permissions>(); UserPermissions = new Dictionary<ulong, Permissions>();
ChannelPermissions = new Dictionary<ulong, Permissions>(); ChannelPermissions = new Dictionary<ulong, Permissions>();
RolePermissions = new Dictionary<ulong, Permissions>(); RolePermissions = new Dictionary<ulong, Permissions>();
CommandCooldowns = new ConcurrentDictionary<string, int>();
Words = new HashSet<string>(); Words = new HashSet<string>();
} }
} }

View File

@ -55,7 +55,7 @@ namespace NadekoBot.Modules.Permissions.Commands
.Alias(Module.Prefix + "cfi") .Alias(Module.Prefix + "cfi")
.Description("Enables or disables automatic deleting of invites on the channel." + .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." + "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("bool")
.Parameter("channel", ParameterType.Optional) .Parameter("channel", ParameterType.Optional)
.Do(async e => .Do(async e =>
@ -95,7 +95,7 @@ namespace NadekoBot.Modules.Permissions.Commands
cgb.CreateCommand(Module.Prefix + "srvrfilterinv") cgb.CreateCommand(Module.Prefix + "srvrfilterinv")
.Alias(Module.Prefix + "sfi") .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") .Parameter("bool")
.Do(async e => .Do(async e =>
{ {

View File

@ -53,7 +53,7 @@ namespace NadekoBot.Modules.Permissions.Commands
.Alias(Module.Prefix + "cfw") .Alias(Module.Prefix + "cfw")
.Description("Enables or disables automatic deleting of messages containing banned words on the channel." + .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." + "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("bool")
.Parameter("channel", ParameterType.Optional) .Parameter("channel", ParameterType.Optional)
.Do(async e => .Do(async e =>
@ -89,7 +89,7 @@ namespace NadekoBot.Modules.Permissions.Commands
cgb.CreateCommand(Module.Prefix + "addfilterword") cgb.CreateCommand(Module.Prefix + "addfilterword")
.Alias(Module.Prefix + "afw") .Alias(Module.Prefix + "afw")
.Description("Adds a new word to the list of filtered words" + .Description("Adds a new word to the list of filtered words" +
"\n**Usage**: ;afw poop") " | ;afw poop")
.Parameter("word", ParameterType.Unparsed) .Parameter("word", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -111,7 +111,7 @@ namespace NadekoBot.Modules.Permissions.Commands
cgb.CreateCommand(Module.Prefix + "rmvfilterword") cgb.CreateCommand(Module.Prefix + "rmvfilterword")
.Alias(Module.Prefix + "rfw") .Alias(Module.Prefix + "rfw")
.Description("Removes the word from the list of filtered words" + .Description("Removes the word from the list of filtered words" +
"\n**Usage**: ;rw poop") " | ;rw poop")
.Parameter("word", ParameterType.Unparsed) .Parameter("word", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -133,7 +133,7 @@ namespace NadekoBot.Modules.Permissions.Commands
cgb.CreateCommand(Module.Prefix + "lstfilterwords") cgb.CreateCommand(Module.Prefix + "lstfilterwords")
.Alias(Module.Prefix + "lfw") .Alias(Module.Prefix + "lfw")
.Description("Shows a list of filtered words" + .Description("Shows a list of filtered words" +
"\n**Usage**: ;lfw") " | ;lfw")
.Do(async e => .Do(async e =>
{ {
try try
@ -152,7 +152,7 @@ namespace NadekoBot.Modules.Permissions.Commands
cgb.CreateCommand(Module.Prefix + "srvrfilterwords") cgb.CreateCommand(Module.Prefix + "srvrfilterwords")
.Alias(Module.Prefix + "sfw") .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") .Parameter("bool")
.Do(async e => .Do(async e =>
{ {

View File

@ -1,5 +1,6 @@
using Discord.Commands; using Discord.Commands;
using Discord.Modules; using Discord.Modules;
using NadekoBot.Classes;
using NadekoBot.Classes.JSONModels; using NadekoBot.Classes.JSONModels;
using NadekoBot.Extensions; using NadekoBot.Extensions;
using NadekoBot.Modules.Games.Commands; using NadekoBot.Modules.Games.Commands;
@ -60,7 +61,7 @@ namespace NadekoBot.Modules.Permissions
cgb.CreateCommand(Prefix + "rolepermscopy") cgb.CreateCommand(Prefix + "rolepermscopy")
.Alias(Prefix + "rpc") .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) .Parameter("from_to", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -88,7 +89,7 @@ namespace NadekoBot.Modules.Permissions
}); });
cgb.CreateCommand(Prefix + "chnlpermscopy") cgb.CreateCommand(Prefix + "chnlpermscopy")
.Alias(Prefix + "cpc") .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) .Parameter("from_to", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -116,7 +117,7 @@ namespace NadekoBot.Modules.Permissions
}); });
cgb.CreateCommand(Prefix + "usrpermscopy") cgb.CreateCommand(Prefix + "usrpermscopy")
.Alias(Prefix + "upc") .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) .Parameter("from_to", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -145,7 +146,7 @@ namespace NadekoBot.Modules.Permissions
cgb.CreateCommand(Prefix + "verbose") cgb.CreateCommand(Prefix + "verbose")
.Alias(Prefix + "v") .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) .Parameter("arg", ParameterType.Required)
.Do(async e => .Do(async e =>
{ {
@ -168,7 +169,7 @@ namespace NadekoBot.Modules.Permissions
cgb.CreateCommand(Prefix + "roleperms") cgb.CreateCommand(Prefix + "roleperms")
.Alias(Prefix + "rp") .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) .Parameter("role", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -194,7 +195,7 @@ namespace NadekoBot.Modules.Permissions
cgb.CreateCommand(Prefix + "chnlperms") cgb.CreateCommand(Prefix + "chnlperms")
.Alias(Prefix + "cp") .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) .Parameter("channel", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -219,7 +220,7 @@ namespace NadekoBot.Modules.Permissions
cgb.CreateCommand(Prefix + "userperms") cgb.CreateCommand(Prefix + "userperms")
.Alias(Prefix + "up") .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) .Parameter("user", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -245,7 +246,7 @@ namespace NadekoBot.Modules.Permissions
.Alias(Prefix + "sm") .Alias(Prefix + "sm")
.Parameter("module", ParameterType.Required) .Parameter("module", ParameterType.Required)
.Parameter("bool", 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 => .Do(async e =>
{ {
try try
@ -269,7 +270,7 @@ namespace NadekoBot.Modules.Permissions
cgb.CreateCommand(Prefix + "srvrcmd").Alias(Prefix + "sc") cgb.CreateCommand(Prefix + "srvrcmd").Alias(Prefix + "sc")
.Parameter("command", ParameterType.Required) .Parameter("command", ParameterType.Required)
.Parameter("bool", 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 => .Do(async e =>
{ {
try try
@ -294,7 +295,7 @@ namespace NadekoBot.Modules.Permissions
.Parameter("module", ParameterType.Required) .Parameter("module", ParameterType.Required)
.Parameter("bool", ParameterType.Required) .Parameter("bool", ParameterType.Required)
.Parameter("role", ParameterType.Unparsed) .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 => .Do(async e =>
{ {
try try
@ -332,7 +333,7 @@ namespace NadekoBot.Modules.Permissions
.Parameter("command", ParameterType.Required) .Parameter("command", ParameterType.Required)
.Parameter("bool", ParameterType.Required) .Parameter("bool", ParameterType.Required)
.Parameter("role", ParameterType.Unparsed) .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 => .Do(async e =>
{ {
try try
@ -370,7 +371,7 @@ namespace NadekoBot.Modules.Permissions
.Parameter("module", ParameterType.Required) .Parameter("module", ParameterType.Required)
.Parameter("bool", ParameterType.Required) .Parameter("bool", ParameterType.Required)
.Parameter("channel", ParameterType.Unparsed) .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 => .Do(async e =>
{ {
try try
@ -413,7 +414,7 @@ namespace NadekoBot.Modules.Permissions
.Parameter("command", ParameterType.Required) .Parameter("command", ParameterType.Required)
.Parameter("bool", ParameterType.Required) .Parameter("bool", ParameterType.Required)
.Parameter("channel", ParameterType.Unparsed) .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 => .Do(async e =>
{ {
try try
@ -451,7 +452,7 @@ namespace NadekoBot.Modules.Permissions
.Parameter("module", ParameterType.Required) .Parameter("module", ParameterType.Required)
.Parameter("bool", ParameterType.Required) .Parameter("bool", ParameterType.Required)
.Parameter("user", ParameterType.Unparsed) .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 => .Do(async e =>
{ {
try try
@ -477,7 +478,7 @@ namespace NadekoBot.Modules.Permissions
.Parameter("command", ParameterType.Required) .Parameter("command", ParameterType.Required)
.Parameter("bool", ParameterType.Required) .Parameter("bool", ParameterType.Required)
.Parameter("user", ParameterType.Unparsed) .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 => .Do(async e =>
{ {
try try
@ -501,7 +502,7 @@ namespace NadekoBot.Modules.Permissions
cgb.CreateCommand(Prefix + "allsrvrmdls").Alias(Prefix + "asm") cgb.CreateCommand(Prefix + "allsrvrmdls").Alias(Prefix + "asm")
.Parameter("bool", ParameterType.Required) .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 => .Do(async e =>
{ {
try try
@ -527,7 +528,7 @@ namespace NadekoBot.Modules.Permissions
cgb.CreateCommand(Prefix + "allsrvrcmds").Alias(Prefix + "asc") cgb.CreateCommand(Prefix + "allsrvrcmds").Alias(Prefix + "asc")
.Parameter("module", ParameterType.Required) .Parameter("module", ParameterType.Required)
.Parameter("bool", 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 => .Do(async e =>
{ {
try try
@ -554,7 +555,7 @@ namespace NadekoBot.Modules.Permissions
cgb.CreateCommand(Prefix + "allchnlmdls").Alias(Prefix + "acm") cgb.CreateCommand(Prefix + "allchnlmdls").Alias(Prefix + "acm")
.Parameter("bool", ParameterType.Required) .Parameter("bool", ParameterType.Required)
.Parameter("channel", ParameterType.Unparsed) .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 => .Do(async e =>
{ {
try try
@ -583,7 +584,7 @@ namespace NadekoBot.Modules.Permissions
.Parameter("module", ParameterType.Required) .Parameter("module", ParameterType.Required)
.Parameter("bool", ParameterType.Required) .Parameter("bool", ParameterType.Required)
.Parameter("channel", ParameterType.Unparsed) .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 => .Do(async e =>
{ {
try try
@ -610,7 +611,7 @@ namespace NadekoBot.Modules.Permissions
cgb.CreateCommand(Prefix + "allrolemdls").Alias(Prefix + "arm") cgb.CreateCommand(Prefix + "allrolemdls").Alias(Prefix + "arm")
.Parameter("bool", ParameterType.Required) .Parameter("bool", ParameterType.Required)
.Parameter("role", ParameterType.Unparsed) .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 => .Do(async e =>
{ {
try try
@ -638,7 +639,7 @@ namespace NadekoBot.Modules.Permissions
.Parameter("module", ParameterType.Required) .Parameter("module", ParameterType.Required)
.Parameter("bool", ParameterType.Required) .Parameter("bool", ParameterType.Required)
.Parameter("role", ParameterType.Unparsed) .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 => .Do(async e =>
{ {
try try
@ -678,7 +679,7 @@ namespace NadekoBot.Modules.Permissions
}); });
cgb.CreateCommand(Prefix + "ubl") 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) .Parameter("user", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.OwnerOnly()) .AddCheck(SimpleCheckers.OwnerOnly())
.Do(async e => .Do(async e =>
@ -694,7 +695,7 @@ namespace NadekoBot.Modules.Permissions
}); });
cgb.CreateCommand(Prefix + "uubl") 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) .Parameter("user", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.OwnerOnly()) .AddCheck(SimpleCheckers.OwnerOnly())
.Do(async e => .Do(async e =>
@ -717,7 +718,7 @@ namespace NadekoBot.Modules.Permissions
}); });
cgb.CreateCommand(Prefix + "cbl") 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) .Parameter("channel", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -732,7 +733,7 @@ namespace NadekoBot.Modules.Permissions
}); });
cgb.CreateCommand(Prefix + "cubl") 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) .Parameter("channel", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -747,7 +748,7 @@ namespace NadekoBot.Modules.Permissions
}); });
cgb.CreateCommand(Prefix + "sbl") 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) .Parameter("server", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.OwnerOnly()) .AddCheck(SimpleCheckers.OwnerOnly())
.Do(async e => .Do(async e =>
@ -776,6 +777,57 @@ namespace NadekoBot.Modules.Permissions
await e.Channel.SendMessage($"`Sucessfully blacklisted server {server.Name}`").ConfigureAwait(false); await e.Channel.SendMessage($"`Sucessfully blacklisted server {server.Name}`").ConfigureAwait(false);
}).ConfigureAwait(false); }).ConfigureAwait(false);
}); });
cgb.CreateCommand(Prefix + "cmdcooldown")
.Alias(Prefix+ "cmdcd")
.Description($"Sets a cooldown per user for a command. Set 0 to clear. | `{Prefix}cmdcd \"some cmd\" 5`")
.Parameter("command", ParameterType.Required)
.Parameter("secs",ParameterType.Required)
.AddCheck(SimpleCheckers.ManageMessages())
.Do(async e =>
{
try
{
var command = PermissionHelper.ValidateCommand(e.GetArg("command"));
var secsStr = e.GetArg("secs").Trim();
int secs;
if (!int.TryParse(secsStr, out secs) || secs < 0 || secs > 3600)
throw new ArgumentOutOfRangeException("secs", "Invalid second parameter. (Must be a number between 0 and 3600)");
PermissionsHandler.SetCommandCooldown(e.Server, command, secs);
if(secs == 0)
await e.Channel.SendMessage($"Command **{command}** has no coooldown now.").ConfigureAwait(false);
else
await e.Channel.SendMessage($"Command **{command}** now has a **{secs} {(secs==1 ? "second" : "seconds")}** cooldown.").ConfigureAwait(false);
}
catch (ArgumentException exArg)
{
await e.Channel.SendMessage(exArg.Message).ConfigureAwait(false);
}
catch (Exception ex)
{
await e.Channel.SendMessage("Something went terribly wrong - " + ex.Message).ConfigureAwait(false);
}
});
cgb.CreateCommand(Prefix + "allcmdcooldowns")
.Alias(Prefix + "acmdcds")
.Description("Shows a list of all commands and their respective cooldowns.")
.Do(async e =>
{
ServerPermissions perms;
PermissionsHandler.PermissionsDict.TryGetValue(e.Server.Id, out perms);
if (perms == null)
return;
if (!perms.CommandCooldowns.Any())
{
await e.Channel.SendMessage("`No command cooldowns set.`").ConfigureAwait(false);
return;
}
await e.Channel.SendMessage(SearchHelper.ShowInPrettyCode(perms.CommandCooldowns.Select(c=>c.Key+ ": "+c.Value+" secs"),s=>$"{s,-30}",2)).ConfigureAwait(false);
});
}); });
} }
} }

View File

@ -80,7 +80,7 @@ namespace NadekoBot.Modules.Pokemon
commands.ForEach(cmd => cmd.Init(cgb)); commands.ForEach(cmd => cmd.Init(cgb));
cgb.CreateCommand(Prefix + "attack") 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("move", ParameterType.Required)
.Parameter("target", ParameterType.Unparsed) .Parameter("target", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
@ -210,7 +210,7 @@ namespace NadekoBot.Modules.Pokemon
}); });
cgb.CreateCommand(Prefix + "heal") 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) .Parameter("target", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -242,7 +242,7 @@ namespace NadekoBot.Modules.Pokemon
return; return;
} }
var target = (usr.Id == e.User.Id) ? "yourself" : usr.Name; 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 //healing
targetStats.Hp = targetStats.MaxHp; targetStats.Hp = targetStats.MaxHp;
if (HP < 0) if (HP < 0)
@ -263,7 +263,7 @@ namespace NadekoBot.Modules.Pokemon
}); });
cgb.CreateCommand(Prefix + "type") 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) .Parameter("target", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -282,7 +282,7 @@ namespace NadekoBot.Modules.Pokemon
}); });
cgb.CreateCommand(Prefix + "settype") 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) .Parameter("targetType", ParameterType.Unparsed)
.Do(async e => .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); 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; 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 //Actually changing the type here
var preTypes = DbHandler.Instance.GetAllRows<UserPokeTypes>(); var preTypes = DbHandler.Instance.GetAllRows<UserPokeTypes>();
Dictionary<long, int> Dict = preTypes.ToDictionary(x => x.UserId, y => y.Id.Value); 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") cgb.CreateCommand(Module.Prefix + "calculate")
.Alias(Module.Prefix + "calc") .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) .Parameter("expression", ParameterType.Unparsed)
.Do(EvalFunc()); .Do(EvalFunc());
} }
@ -49,11 +49,11 @@ namespace NadekoBot.Modules.Searches.Commands
string result = parser.Parse(expression).ToString(); string result = parser.Parse(expression).ToString();
return result; return result;
} }
catch (OverflowException e) catch (OverflowException)
{ {
return $"Overflow error on {expression}"; return $"Overflow error on {expression}";
} }
catch (FormatException e) catch (FormatException)
{ {
return $"\"{expression}\" was not formatted correctly"; return $"\"{expression}\" was not formatted correctly";
} }

View File

@ -75,7 +75,7 @@ namespace NadekoBot.Modules.Searches.Commands
internal override void Init(CommandGroupBuilder cgb) internal override void Init(CommandGroupBuilder cgb)
{ {
cgb.CreateCommand(Module.Prefix + "lolchamp") 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("champ", ParameterType.Required)
.Parameter("position", ParameterType.Unparsed) .Parameter("position", ParameterType.Unparsed)
.Do(async e => .Do(async e =>

View File

@ -17,7 +17,7 @@ namespace NadekoBot.Modules.Searches.Commands
internal override void Init(CommandGroupBuilder cgb) internal override void Init(CommandGroupBuilder cgb)
{ {
cgb.CreateCommand(Module.Prefix + "osu") 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("usr", ParameterType.Required)
.Parameter("mode", ParameterType.Unparsed) .Parameter("mode", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
@ -56,7 +56,7 @@ namespace NadekoBot.Modules.Searches.Commands
}); });
cgb.CreateCommand(Module.Prefix + "osu b") 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) .Parameter("map", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -88,7 +88,7 @@ namespace NadekoBot.Modules.Searches.Commands
}); });
cgb.CreateCommand(Module.Prefix + "osu top5") 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("usr", ParameterType.Required)
.Parameter("mode", ParameterType.Unparsed) .Parameter("mode", ParameterType.Unparsed)
.Do(async e => .Do(async e =>

View File

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

View File

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

View File

@ -15,6 +15,7 @@ using System.Drawing;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net.Http; using System.Net.Http;
using System.Web;
namespace NadekoBot.Modules.Searches namespace NadekoBot.Modules.Searches
{ {
@ -47,7 +48,7 @@ namespace NadekoBot.Modules.Searches
commands.ForEach(cmd => cmd.Init(cgb)); commands.ForEach(cmd => cmd.Init(cgb));
cgb.CreateCommand(Prefix + "we") 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("city", ParameterType.Required)
.Parameter("country", ParameterType.Required) .Parameter("country", ParameterType.Required)
.Do(async e => .Do(async e =>
@ -157,7 +158,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
}); });
cgb.CreateCommand(Prefix + "i") 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) .Parameter("query", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -183,7 +184,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
}); });
cgb.CreateCommand(Prefix + "ir") 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) .Parameter("query", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -219,8 +220,21 @@ $@"🌍 **Weather for** 【{obj["target"]}】
.ConfigureAwait(false); .ConfigureAwait(false);
}); });
cgb.CreateCommand(Prefix + "google")
.Alias(Prefix + "g")
.Description("Get a google search link for some terms.")
.Parameter("terms", ParameterType.Unparsed)
.Do(async e =>
{
var terms = e.GetArg("terms")?.Trim().Replace(' ', '+');
if (string.IsNullOrWhiteSpace(terms))
return;
await e.Channel.SendMessage($"https://google.com/search?q={ HttpUtility.UrlEncode(terms) }")
.ConfigureAwait(false);
});
cgb.CreateCommand(Prefix + "hs") 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) .Parameter("name", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -261,7 +275,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
}); });
cgb.CreateCommand(Prefix + "ud") 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) .Parameter("query", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -290,7 +304,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
}); });
// thanks to Blaubeerwald // thanks to Blaubeerwald
cgb.CreateCommand(Prefix + "#") 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) .Parameter("query", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -364,15 +378,15 @@ $@"🌍 **Weather for** 【{obj["target"]}】
}); });
cgb.CreateCommand(Prefix + "magicitem") cgb.CreateCommand(Prefix + "magicitem")
.Alias(Prefix + "mi") .Alias(Prefix + "mi")
.Description("Shows a random magicitem from <https://1d4chan.org/wiki/List_of_/tg/%27s_magic_items>") .Description("Shows a random magicitem from <https://1d4chan.org/wiki/List_of_/tg/%27s_magic_items>")
.Do(async e => .Do(async e =>
{ {
var magicItems = JsonConvert.DeserializeObject<List<MagicItem>>(File.ReadAllText("data/magicitems.json")); var magicItems = JsonConvert.DeserializeObject<List<MagicItem>>(File.ReadAllText("data/magicitems.json"));
var item = magicItems[rng.Next(0, magicItems.Count)].ToString(); var item = magicItems[rng.Next(0, magicItems.Count)].ToString();
await e.Channel.SendMessage(item).ConfigureAwait(false); await e.Channel.SendMessage(item).ConfigureAwait(false);
}); });
cgb.CreateCommand(Prefix + "revav") cgb.CreateCommand(Prefix + "revav")
.Description("Returns a google reverse image search for someone's avatar.") .Description("Returns a google reverse image search for someone's avatar.")
@ -404,7 +418,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
}); });
cgb.CreateCommand(Prefix + "safebooru") 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) .Parameter("tag", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -431,7 +445,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
}); });
cgb.CreateCommand(Prefix + "clr") 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) .Parameter("color", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
@ -480,7 +494,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
cgb.CreateCommand(Prefix + "av") cgb.CreateCommand(Prefix + "av")
.Alias(Prefix + "avatar") .Alias(Prefix + "avatar")
.Parameter("mention", ParameterType.Required) .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 => .Do(async e =>
{ {
var usr = e.Channel.FindUsers(e.GetArg("mention")).FirstOrDefault(); var usr = e.Channel.FindUsers(e.GetArg("mention")).FirstOrDefault();

View File

@ -14,7 +14,7 @@ namespace NadekoBot.Modules.Translator
{ {
cgb.CreateCommand(Module.Prefix + "translate") cgb.CreateCommand(Module.Prefix + "translate")
.Alias(Module.Prefix + "trans") .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("langs", ParameterType.Required)
.Parameter("text", ParameterType.Unparsed) .Parameter("text", ParameterType.Unparsed)
.Do(TranslateFunc()); .Do(TranslateFunc());

View File

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

View File

@ -18,7 +18,7 @@ namespace NadekoBot.Modules.Utility.Commands
{ {
cgb.CreateCommand(Module.Prefix + "serverinfo") cgb.CreateCommand(Module.Prefix + "serverinfo")
.Alias(Module.Prefix + "sinfo") .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) .Parameter("server", ParameterType.Optional)
.Do(async e => .Do(async e =>
{ {
@ -49,7 +49,7 @@ namespace NadekoBot.Modules.Utility.Commands
cgb.CreateCommand(Module.Prefix + "channelinfo") cgb.CreateCommand(Module.Prefix + "channelinfo")
.Alias(Module.Prefix + "cinfo") .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) .Parameter("channel", ParameterType.Optional)
.Do(async e => .Do(async e =>
{ {
@ -71,7 +71,7 @@ namespace NadekoBot.Modules.Utility.Commands
cgb.CreateCommand(Module.Prefix + "userinfo") cgb.CreateCommand(Module.Prefix + "userinfo")
.Alias(Module.Prefix + "uinfo") .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) .Parameter("user", ParameterType.Optional)
.Do(async e => .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. " + .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. " + "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. " + "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("meorchannel", ParameterType.Required)
.Parameter("time", ParameterType.Required) .Parameter("time", ParameterType.Required)
.Parameter("message", ParameterType.Unparsed) .Parameter("message", ParameterType.Unparsed)

View File

@ -99,7 +99,7 @@ namespace NadekoBot.Modules.Utility
.Description("Shows some basic stats for Nadeko.") .Description("Shows some basic stats for Nadeko.")
.Do(async e => .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") cgb.CreateCommand(Prefix + "dysyd")

View File

@ -41,8 +41,9 @@ namespace NadekoBot
public static LocalizedStrings Locale { get; set; } = new LocalizedStrings(); public static LocalizedStrings Locale { get; set; } = new LocalizedStrings();
public static string BotMention { get; set; } = ""; public static string BotMention { get; set; } = "";
public static bool Ready { get; set; } = false; public static bool Ready { get; set; } = false;
public static Action OnReady { get; set; } = delegate { };
private static Channel OwnerPrivateChannel { get; set; } private static List<Channel> OwnerPrivateChannels { get; set; }
private static void Main() private static void Main()
{ {
@ -196,7 +197,7 @@ namespace NadekoBot
return; return;
} }
#if NADEKO_RELEASE #if NADEKO_RELEASE
await Task.Delay(100000).ConfigureAwait(false); await Task.Delay(90000).ConfigureAwait(false);
#else #else
await Task.Delay(1000).ConfigureAwait(false); await Task.Delay(1000).ConfigureAwait(false);
#endif #endif
@ -205,15 +206,19 @@ namespace NadekoBot
Console.WriteLine(await NadekoStats.Instance.GetStats().ConfigureAwait(false)); Console.WriteLine(await NadekoStats.Instance.GetStats().ConfigureAwait(false));
Console.WriteLine("-----------------"); Console.WriteLine("-----------------");
try
{
OwnerPrivateChannel = await Client.CreatePrivateChannel(Creds.OwnerIds[0]).ConfigureAwait(false);
}
catch
{
Console.WriteLine("Failed creating private channel with the first owner listed in credentials.json");
}
OwnerPrivateChannels = new List<Channel>(Creds.OwnerIds.Length);
foreach (var id in Creds.OwnerIds)
{
try
{
OwnerPrivateChannels.Add(await Client.CreatePrivateChannel(id).ConfigureAwait(false));
}
catch
{
Console.WriteLine($"Failed creating private channel with the owner {id} listed in credentials.json");
}
}
Client.ClientAPI.SendingRequest += (s, e) => Client.ClientAPI.SendingRequest += (s, e) =>
{ {
var request = e.Request as Discord.API.Client.Rest.SendMessageRequest; var request = e.Request as Discord.API.Client.Rest.SendMessageRequest;
@ -225,6 +230,7 @@ namespace NadekoBot
}; };
PermissionsHandler.Initialize(); PermissionsHandler.Initialize();
NadekoBot.Ready = true; NadekoBot.Ready = true;
NadekoBot.OnReady();
}); });
Console.WriteLine("Exiting..."); Console.WriteLine("Exiting...");
Console.ReadKey(); Console.ReadKey();
@ -234,8 +240,18 @@ namespace NadekoBot
public static async Task SendMessageToOwner(string message) public static async Task SendMessageToOwner(string message)
{ {
if (Config.ForwardMessages && OwnerPrivateChannel != null) if (Config.ForwardMessages && OwnerPrivateChannels.Any())
await OwnerPrivateChannel.SendMessage(message).ConfigureAwait(false); 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; private static bool repliedRecently = false;
@ -248,8 +264,8 @@ namespace NadekoBot
if (ConfigHandler.IsBlackListed(e)) if (ConfigHandler.IsBlackListed(e))
return; return;
if (Config.ForwardMessages && !NadekoBot.Creds.OwnerIds.Contains(e.User.Id) && OwnerPrivateChannel != null) if (Config.ForwardMessages && !NadekoBot.Creds.OwnerIds.Contains(e.User.Id) && OwnerPrivateChannels.Any())
await OwnerPrivateChannel.SendMessage(e.User + ": ```\n" + e.Message.Text + "\n```").ConfigureAwait(false); await SendMessageToOwner(e.User + ": ```\n" + e.Message.Text + "\n```").ConfigureAwait(false);
if (repliedRecently) return; if (repliedRecently) return;
@ -263,5 +279,3 @@ namespace NadekoBot
} }
} }
} }
//95520984584429568 meany

View File

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

View File

@ -3,25 +3,14 @@ using NadekoBot.Extensions;
using Newtonsoft.Json; using Newtonsoft.Json;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Runtime.Serialization;
namespace NadekoBot.Classes.JSONModels namespace NadekoBot.Classes.JSONModels
{ {
public class Configuration 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] [JsonIgnore]
public List<Quote> Quotes { get; set; } = new List<Quote>(); public static readonly Dictionary<string, List<string>> DefaultCustomReactions = new Dictionary<string, List<string>>
[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>>()
{ {
{@"\o\", new List<string>() {@"\o\", new List<string>()
{ "/o/" } }, { "/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 List<string> RotatingStatuses { get; set; } = new List<string>();
public CommandPrefixesModel CommandPrefixes { get; set; } = new CommandPrefixesModel(); public CommandPrefixesModel CommandPrefixes { get; set; } = new CommandPrefixesModel();
public HashSet<ulong> ServerBlacklist { get; set; } = new HashSet<ulong>(); public HashSet<ulong> ServerBlacklist { get; set; } = new HashSet<ulong>();
@ -104,6 +109,22 @@ namespace NadekoBot.Classes.JSONModels
143515953525817344 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; } = public string[] _8BallResponses { get; set; } =
{ {
@ -154,7 +175,7 @@ Nadeko Support Server: <https://discord.gg/0ehQwTK2RBjAxzEY>";
public string Conversations { get; set; } = "<@{0}>"; public string Conversations { get; set; } = "<@{0}>";
public string ClashOfClans { get; set; } = ","; public string ClashOfClans { get; set; } = ",";
public string Help { get; set; } = "-"; public string Help { get; set; } = "-";
public string Music { get; set; } = "!m"; public string Music { get; set; } = "!!";
public string Trello { get; set; } = "trello "; public string Trello { get; set; } = "trello ";
public string Games { get; set; } = ">"; public string Games { get; set; } = ">";
public string Gambling { get; set; } = "$"; public string Gambling { get; set; } = "$";

View File

@ -7,7 +7,7 @@ namespace NadekoBot.Classes.JSONModels
public class Credentials public class Credentials
{ {
public string Token { get; set; } = ""; public string Token { get; set; } = "";
public string ClientId { get; set; } = "116275390695079945"; public string ClientId { get; set; } = "170254782546575360";
public ulong BotId { get; set; } = 1231231231231; public ulong BotId { get; set; } = 1231231231231;
public ulong[] OwnerIds { get; set; } = { 123123123123, 5675675679845 }; public ulong[] OwnerIds { get; set; } = { 123123123123, 5675675679845 };
public string GoogleAPIKey { get; set; } = ""; public string GoogleAPIKey { get; set; } = "";

View File

@ -1,6 +1,6 @@
{ {
"Token": "", "Token": "",
"ClientId": "116275390695079945", "ClientId": "170254782546575360",
"BotId": 1231231231231, "BotId": 1231231231231,
"OwnerIds": [ "OwnerIds": [
123123123123, 123123123123,

View File

@ -1,8 +1,10 @@
{ {
"DontJoinServers": false, "DontJoinServers": false,
"ForwardMessages": true, "ForwardMessages": true,
"ForwardToAllOwners": false,
"IsRotatingStatus": false, "IsRotatingStatus": false,
"BufferSize": 4194304, "BufferSize": 4194304,
"Quotes": [],
"RemindMessageFormat": "❗⏰**I've been told to remind you to '%message%' now by %user%.**⏰❗", "RemindMessageFormat": "❗⏰**I've been told to remind you to '%message%' now by %user%.**⏰❗",
"CustomReactions": { "CustomReactions": {
"\\o\\": [ "\\o\\": [
@ -81,7 +83,7 @@
"Conversations": "<@{0}>", "Conversations": "<@{0}>",
"ClashOfClans": ",", "ClashOfClans": ",",
"Help": "-", "Help": "-",
"Music": "!m", "Music": "!!",
"Trello": "trello ", "Trello": "trello ",
"Games": ">", "Games": ">",
"Gambling": "$", "Gambling": "$",

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

@ -1,10 +1,10 @@
######For more information and how to setup your own NadekoBot, go to: **http://github.com/Kwoth/NadekoBot/** ######For more information and how to setup your own NadekoBot, go to: **http://github.com/Kwoth/NadekoBot/**
######You can donate on paypal: `nadekodiscordbot@gmail.com` or Bitcoin `17MZz1JAqME39akMLrVT4XBPffQJ2n1EPa` ######You can donate on paypal: `nadekodiscordbot@gmail.com`
#NadekoBot List Of Commands #NadekoBot List Of Commands
Version: `NadekoBot v0.9.6030.3793` Version: `NadekoBot v0.9.6045.31170`
### Help ### Help
Command and aliases | Description | Usage Command and aliases | Description | Usage
----------------|--------------|------- ----------------|--------------|-------
`-h`, `-help`, `@BotName help`, `@BotName h`, `~h` | Either shows a help for a single command, or PMs you help link if no arguments are specified. | '-h !m q' or just '-h' `-h`, `-help`, `@BotName help`, `@BotName h`, `~h` | Either shows a help for a single command, or PMs you help link if no arguments are specified. | '-h !m q' or just '-h'
`-hgit` | Generates the commandlist.md file. **Bot Owner Only!** `-hgit` | Generates the commandlist.md file. **Bot Owner Only!**
@ -14,7 +14,7 @@ Command and aliases | Description | Usage
`-commands`, `.commands` | List all of the bot's commands from a certain module. `-commands`, `.commands` | List all of the bot's commands from a certain module.
### Administration ### Administration
Command and aliases | Description | Usage Command and aliases | Description | Usage
----------------|--------------|------- ----------------|--------------|-------
`.grdel` | Toggles automatic deletion of greet and bye messages. `.grdel` | Toggles automatic deletion of greet and bye messages.
`.greet` | Toggles anouncements on the current channel when someone joins the server. `.greet` | Toggles anouncements on the current channel when someone joins the server.
@ -25,6 +25,7 @@ Command and aliases | Description | Usage
`.greetpm` | Toggles whether the greet messages will be sent in a PM or in the text channel. `.greetpm` | Toggles whether the greet messages will be sent in a PM or in the text channel.
`.spmom` | Toggles whether mentions of other offline users on your server will send a pm to them. `.spmom` | Toggles whether mentions of other offline users on your server will send a pm to them.
`.logserver` | Toggles logging in this channel. Logs every message sent/deleted/edited on the server. **Bot Owner Only!** `.logserver` | Toggles logging in this channel. Logs every message sent/deleted/edited on the server. **Bot Owner Only!**
`.logignore`, `Toggles whether the .logserver command ignores this channel. Useful if you have hidden admin channel and public log channel.` |
`.userpresence` | Starts logging to this channel when someone from the server goes online/offline/idle. `.userpresence` | Starts logging to this channel when someone from the server goes online/offline/idle.
`.voicepresence` | Toggles logging to this channel whenever someone joins or leaves a voice channel you are in right now. `.voicepresence` | Toggles logging to this channel whenever someone joins or leaves a voice channel you are in right now.
`.repeatinvoke`, `.repinv` | Immediately shows the repeat message and restarts the timer. `.repeatinvoke`, `.repinv` | Immediately shows the repeat message and restarts the timer.
@ -42,12 +43,13 @@ Command and aliases | Description | Usage
`.asar` | Adds a role, or list of roles separated by whitespace(use quotations for multiword roles) to the list of self-assignable roles. | .asar Gamer `.asar` | Adds a role, or list of roles separated by whitespace(use quotations for multiword roles) to the list of self-assignable roles. | .asar Gamer
`.rsar` | Removes a specified role from the list of self-assignable roles. `.rsar` | Removes a specified role from the list of self-assignable roles.
`.lsar` | Lists all self-assignable roles. `.lsar` | Lists all self-assignable roles.
`.togglexclsar`, `.tesar` | toggle whether the self-assigned roles should be exclusive
`.iam` | Adds a role to you that you choose. Role must be on a list of self-assignable roles. | .iam Gamer `.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 `.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% `.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 `.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` `.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) `.delcustreact`, `.dcr` | Deletes a custom reaction with given name (and index)
`.autoassignrole`, `.aar` | Automaticaly assigns a specified role to every user who joins the server. Type `.aar` to disable, `.aar Role Name` to enable `.autoassignrole`, `.aar` | Automaticaly assigns a specified role to every user who joins the server. Type `.aar` to disable, `.aar Role Name` to enable
`.leave` | Makes Nadeko leave the server. Either name or id required. | `.leave 123123123331` `.leave` | Makes Nadeko leave the server. Either name or id required. | `.leave 123123123331`
@ -86,11 +88,10 @@ Command and aliases | Description | Usage
`.donators` | List of lovely people who donated to keep this project alive. `.donators` | List of lovely people who donated to keep this project alive.
`.donadd` | Add a donator to the database. `.donadd` | Add a donator to the database.
`.announce` | Sends a message to all servers' general channel bot is connected to.**Bot Owner Only!** | .announce Useless spam `.announce` | Sends a message to all servers' general channel bot is connected to.**Bot Owner Only!** | .announce Useless spam
`.leave` | Leaves a server with a supplied ID. | `.leave 493243292839` `.savechat` | Saves a number of messages to a text file and sends it to you. **Bot Owner Only** | `.chatsave 150`
`.savechat` | Saves a number of messages to a text file and sends it to you. **Bot Owner Only** | `.chatsave 150`
### Utility ### Utility
Command and aliases | Description | Usage Command and aliases | Description | Usage
----------------|--------------|------- ----------------|--------------|-------
`.remind` | 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. | `.remind me 1d5h Do something` or `.remind #general Start now!` `.remind` | 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. | `.remind me 1d5h Do something` or `.remind #general Start now!`
`.remindmsg` | Sets message for when the remind is triggered. Available placeholders are %user% - user who ran the command, %message% - Message specified in the remind, %target% - target channel of the remind. **Bot Owner Only!** `.remindmsg` | Sets message for when the remind is triggered. Available placeholders are %user% - user who ran the command, %message% - Message specified in the remind, %target% - target channel of the remind. **Bot Owner Only!**
@ -108,7 +109,7 @@ Command and aliases | Description | Usage
`.roles` | List all roles on this server or a single user if specified. `.roles` | List all roles on this server or a single user if specified.
### Permissions ### Permissions
Command and aliases | Description | Usage Command and aliases | Description | Usage
----------------|--------------|------- ----------------|--------------|-------
`;chnlfilterinv`, `;cfi` | 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. | ;cfi enable #general-chat `;chnlfilterinv`, `;cfi` | 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. | ;cfi enable #general-chat
`;srvrfilterinv`, `;sfi` | Enables or disables automatic deleting of invites on the server. | ;sfi disable `;srvrfilterinv`, `;sfi` | Enables or disables automatic deleting of invites on the server. | ;sfi disable
@ -126,59 +127,62 @@ Command and aliases | Description | Usage
`;roleperms`, `;rp` | Shows banned permissions for a certain role. No argument means for everyone. | ;rp AwesomeRole `;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 `;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 `;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 `;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 `;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] `;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 [role_name] `;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 [channel_name] `;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 [channel_name] `;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 [user_name] `;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 [user_name] `;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] `;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] `;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] `;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] [channel_name] `;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] [role_name] `;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] [role_name] `;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] `;ubl` | Blacklists a mentioned user. | ;ubl [user_mention]
`;uubl` | Unblacklists a mentioned user. | ;uubl [user_mention] `;uubl` | Unblacklists a mentioned user. | ;uubl [user_mention]
`;cbl` | Blacklists a mentioned channel (#general for example). | ;cbl [channel_mention] `;cbl` | Blacklists a mentioned channel (#general for example). | ;cbl #some_channel
`;cubl` | Unblacklists a mentioned channel (#general for example). | ;cubl [channel_mention] `;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] `;sbl` | Blacklists a server by a name or id (#general for example). **BOT OWNER ONLY** | ;sbl [servername/serverid]
`;cmdcooldown`, `;cmdcd` | Sets a cooldown per user for a command. Set 0 to clear. | `;cmdcd "some cmd" 5`
`;allcmdcooldowns`, `;acmdcds` | Shows a list of all commands and their respective cooldowns.
### Conversations ### Conversations
Command and aliases | Description | Usage Command and aliases | Description | Usage
----------------|--------------|------- ----------------|--------------|-------
`..` | Adds a new quote with the specified name (single word) and message (no limit). | .. abc My message `..` | Adds a new quote with the specified name (single word) and message (no limit). | .. abc My message
`...` | Shows a random quote with a specified name. | .. abc `...` | 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` `..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 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 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 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. `@BotName how are you`, `@BotName how are you?` | Replies positive only if bot owner is online.
`@BotName fire` | Shows a unicode fire message. Optional parameter [x] tells her how many times to repeat the fire. | @NadekoBot fire [x] `@BotName fire` | Shows a unicode fire message. Optional parameter [x] tells her how many times to repeat the fire. | @NadekoBot fire [x]
`@BotName slm` | Shows the message where you were last mentioned in this channel (checks last 10k messages)
`@BotName dump` | Dumps all of the invites it can to dump.txt.** Owner Only.** `@BotName dump` | Dumps all of the invites it can to dump.txt.** Owner Only.**
`@BotName ab` | Try to get 'abalabahaha' `@BotName ab` | Try to get 'abalabahaha'
### Gambling ### Gambling
Command and aliases | Description | Usage Command and aliases | Description | Usage
----------------|--------------|------- ----------------|--------------|-------
`$draw` | Draws a card from the deck.If you supply number [x], she draws up to 5 cards from the deck. | $draw [x] `$draw` | Draws a card from the deck.If you supply number [x], she draws up to 5 cards from the deck. | $draw [x]
`$shuffle`, `$sh` | Reshuffles all cards back into the deck. `$shuffle`, `$sh` | Reshuffles all cards back into the deck.
`$flip` | Flips coin(s) - heads or tails, and shows an image. | `$flip` or `$flip 3` `$flip` | Flips coin(s) - heads or tails, and shows an image. | `$flip` or `$flip 3`
`$betflip`, `$bf` | Bet to guess will the result be heads or tails. Guessing award you double flowers you've bet. | `$bf 5 heads` or `$bf 3 t`
`$roll` | 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. | $roll or $roll 7 or $roll 3d5 `$roll` | 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. | $roll or $roll 7 or $roll 3d5
`$rolluo` | 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
`$nroll` | Rolls in a given range. | `$nroll 5` (rolls 0-5) or `$nroll 5-15` `$nroll` | Rolls in a given range. | `$nroll 5` (rolls 0-5) or `$nroll 5-15`
`$raffle` | Prints a name and ID of a random user from the online list from the (optional) role. `$raffle` | Prints a name and ID of a random user from the online list from the (optional) role.
`$$$` | Check how much NadekoFlowers a person has. (Defaults to yourself) | `$$$` or `$$$ @Someone` `$$$` | Check how much NadekoFlowers a person has. (Defaults to yourself) | `$$$` or `$$$ @Someone`
`$give` | Give someone a certain amount of NadekoFlowers `$give` | Give someone a certain amount of NadekoFlowers
`$award` | Gives someone a certain amount of flowers. **Bot Owner Only!** | `$award 100 @person` `$award` | Gives someone a certain amount of flowers. **Bot Owner Only!** | `$award 100 @person`
`$take` | Takes a certain amount of flowers from someone. **Bot Owner Only!** `$take` | Takes a certain amount of flowers from someone. **Bot Owner Only!**
`$betroll`, `$br` | Bets a certain amount of NadekoFlowers and rolls a dice. Rolling over 66 yields x2 flowers, over 90 - x3 and 100 x10. | $br 5
`$leaderboard`, `$lb` | `$leaderboard`, `$lb` |
### Games ### Games
Command and aliases | Description | Usage Command and aliases | Description | Usage
----------------|--------------|------- ----------------|--------------|-------
`>t` | 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. | `>t nohint` or `>t 5 nohint` `>t` | 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. | `>t nohint` or `>t 5 nohint`
`>tl` | Shows a current trivia leaderboard. `>tl` | Shows a current trivia leaderboard.
@ -190,7 +194,7 @@ Command and aliases | Description | Usage
`>pollend` | Stops active poll on this server and prints the results in this channel. `>pollend` | Stops active poll on this server and prints the results in this channel.
`>pick` | Picks a flower planted 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) `>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 `>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 `>choose` | Chooses a thing from a list of things | >choose Get up;Sleep;Sleep more
`>8ball` | Ask the 8ball a yes/no question. `>8ball` | Ask the 8ball a yes/no question.
@ -198,42 +202,44 @@ Command and aliases | Description | Usage
`>linux` | Prints a customizable Linux interjection | `>linux Spyware Windows` `>linux` | Prints a customizable Linux interjection | `>linux Spyware Windows`
### Music ### Music
Command and aliases | Description | Usage Command and aliases | Description | Usage
----------------|--------------|------- ----------------|--------------|-------
`!m next`, `!m n`, `!m skip` | Goes to the next song in the queue. You have to be in the same voice channel as the bot. | `!m n` `!!next`, `!!n`, `!!skip` | Goes to the next song in the queue. You have to be in the same voice channel as the bot. | `!m n`
`!m stop`, `!m s` | Stops the music and clears the playlist. Stays in the channel. | `!m s` `!!stop`, `!!s` | Stops the music and clears the playlist. Stays in the channel. | `!m s`
`!m destroy`, `!m d` | Completely stops the music and unbinds the bot from the channel. (may cause weird behaviour) | `!m d` `!!destroy`, `!!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` `!!pause`, `!!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` `!!queue`, `!!q`, `!!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 listqueue`, `!m lq` | Lists 15 currently queued songs per page. Default page is 1. | `!m lq` or `!m lq 2` `!!soundcloudqueue`, `!!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 nowplaying`, `!m np` | Shows the song currently playing. | `!m np` `!!listqueue`, `!!lq` | Lists 15 currently queued songs per page. Default page is 1. | `!m lq` or `!m lq 2`
`!m volume`, `!m vol` | Sets the music volume 0-100% | `!m vol 50` `!!nowplaying`, `!!np` | Shows the song currently playing. | `!m np`
`!m defvol`, `!m dv` | Sets the default music volume when music playback is started (0-100). Persists through restarts. | `!m dv 80` `!!volume`, `!!vol` | Sets the music volume 0-100% | `!m vol 50`
`!m mute`, `!m min` | Sets the music volume to 0% | `!m min` `!!defvol`, `!!dv` | Sets the default music volume when music playback is started (0-100). Persists through restarts. | `!m dv 80`
`!m max` | Sets the music volume to 100% (real max is actually 150%). | `!m max` `!!mute`, `!!min` | Sets the music volume to 0% | `!m min`
`!m half` | Sets the music volume to 50%. | `!m half` `!!max` | Sets the music volume to 100%. | `!m max`
`!m shuffle`, `!m sh` | Shuffles the current playlist. | `!m sh` `!!half` | Sets the music volume to 50%. | `!m half`
`!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` `!!shuffle`, `!!sh` | Shuffles the current playlist. | `!m sh`
`!m soundcloudpl`, `!m scpl` | Queue a soundcloud playlist using a link. | `!m scpl https://soundcloud.com/saratology/sets/symphony` `!!playlist`, `!!pl` | Queues up to 500 songs from a youtube playlist specified by a link, or keywords. | `!m pl playlist link or name`
`!m localplaylst`, `!m lopl` | Queues all songs from a directory. **Bot Owner Only!** | `!m lopl C:/music/classical` `!!soundcloudpl`, `!!scpl` | Queue a soundcloud playlist using a link. | `!m scpl https://soundcloud.com/saratology/sets/symphony`
`!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` `!!localplaylst`, `!!lopl` | Queues all songs from a directory. **Bot Owner Only!** | `!m lopl C:/music/classical`
`!m local`, `!m lo` | Queues a local file by specifying a full path. **Bot Owner Only!** | `!m lo C:/music/mysong.mp3` `!!radio`, `!!ra` | 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`
`!m move`, `!m mv` | Moves the bot to your voice channel. (works only if music is already playing) | `!m mv` `!!local`, `!!lo` | Queues a local file by specifying a full path. **Bot Owner Only!** | `!m lo C:/music/mysong.mp3`
`!m remove`, `!m rm` | Remove a song by its # in the queue, or 'all' to remove whole queue. | `!m rm 5` `!!move`, `!!mv` | Moves the bot to your voice channel. (works only if music is already playing) | `!m mv`
`!m movesong`, `!m ms` | Moves a song from one position to another. | `!m ms` 5>3 `!!remove`, `!!rm` | Remove a song by its # in the queue, or 'all' to remove whole queue. | `!m rm 5`
`!m cleanup` | Cleans up hanging voice connections. **Bot Owner Only!** | `!m cleanup` `!!movesong`, `!!ms` | Moves a song from one position to another. | `!! ms` 5>3
`!m reptcursong`, `!m rcs` | Toggles repeat of current song. | `!m rcs` `!!setmaxqueue`, `!!smq` | Sets a maximum queue size. Supply 0 or no argument to have no limit. | `!! smq` 50 or `!! smq`
`!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` `!!cleanup` | Cleans up hanging voice connections. **Bot Owner Only!** | `!m cleanup`
`!m save` | Saves a playlist under a certain name. Name must be no longer than 20 characters and mustn't contain dashes. | `!m save classical1` `!!reptcursong`, `!!rcs` | Toggles repeat of current song. | `!m rcs`
`!m load` | Loads a playlist under a certain name. | `!m load classical-1` `!!rpeatplaylst`, `!!rpl` | Toggles repeat of all songs in the queue (every song that finishes is added to the end of the queue). | `!m rpl`
`!m playlists`, `!m pls` | Lists all playlists. Paginated. 20 per page. Default page is 0. | `!m pls 1` `!!save` | Saves a playlist under a certain name. Name must be no longer than 20 characters and mustn't contain dashes. | `!m save classical1`
`!m deleteplaylist`, `!m delpls` | Deletes a saved playlist. Only if you made it or if you are the bot owner. | `!m delpls animu-5` `!!load` | Loads a playlist under a certain name. | `!m load classical-1`
`!m goto` | Goes to a specific time in seconds in a song. `!!playlists`, `!!pls` | Lists all playlists. Paginated. 20 per page. Default page is 0. | `!m pls 1`
`!m getlink`, `!m gl` | Shows a link to the currently playing song. `!!deleteplaylist`, `!!delpls` | Deletes a saved playlist. Only if you made it or if you are the bot owner. | `!m delpls animu-5`
`!m autoplay`, `!m ap` | Toggles autoplay - When the song is finished, automatically queue a related youtube song. (Works only for youtube songs and when queue is empty) `!!goto` | Goes to a specific time in seconds in a song.
`!!getlink`, `!!gl` | Shows a link to the currently playing song.
`!!autoplay`, `!!ap` | Toggles autoplay - When the song is finished, automatically queue a related youtube song. (Works only for youtube songs and when queue is empty)
### Searches ### Searches
Command and aliases | Description | Usage Command and aliases | Description | Usage
----------------|--------------|------- ----------------|--------------|-------
`~lolchamp` | 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 `~lolchamp` | 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
`~lolban` | Shows top 6 banned champions ordered by ban rate. Ban these champions and you will be Plat 5 in no time. `~lolban` | Shows top 6 banned champions ordered by ban rate. Ban these champions and you will be Plat 5 in no time.
@ -253,9 +259,9 @@ Command and aliases | Description | Usage
`~osu b` | Shows information about an osu beatmap. | ~osu b https://osu.ppy.sh/s/127712 `~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 `~osu top5` | Displays a user's top 5 plays. | ~osu top5 Name
`~pokemon`, `~poke` | Searches for a pokemon. `~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/ `~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"` `~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 `~we` | Shows weather data for a specified city and a country. BOTH ARE REQUIRED. Use country abbrevations. | ~we Moscow RF
`~yt` | Searches youtubes and shows the first result `~yt` | Searches youtubes and shows the first result
`~ani`, `~anime`, `~aq` | Queries anilist for an anime and shows the first result. `~ani`, `~anime`, `~aq` | Queries anilist for an anime and shows the first result.
@ -265,6 +271,7 @@ Command and aliases | Description | Usage
`~i` | Pulls the first image found using a search parameter. Use ~ir for different results. | ~i cute kitten `~i` | Pulls the first image found using a search parameter. Use ~ir for different results. | ~i cute kitten
`~ir` | Pulls a random image using a search parameter. | ~ir cute kitten `~ir` | Pulls a random image using a search parameter. | ~ir cute kitten
`~lmgtfy` | Google something for an idiot. `~lmgtfy` | Google something for an idiot.
`~google`, `~g` | Get a google search link for some terms.
`~hs` | Searches for a Hearthstone card and shows its image. Takes a while to complete. | ~hs Ysera `~hs` | Searches for a Hearthstone card and shows its image. Takes a while to complete. | ~hs Ysera
`~ud` | Searches Urban Dictionary for a word. | ~ud Pineapple `~ud` | Searches Urban Dictionary for a word. | ~ud Pineapple
`~#` | Searches Tagdef.com for a hashtag. | ~# ff `~#` | Searches Tagdef.com for a hashtag. | ~# ff
@ -283,7 +290,7 @@ Command and aliases | Description | Usage
`~av`, `~avatar` | Shows a mentioned person's avatar. | ~av @X `~av`, `~avatar` | Shows a mentioned person's avatar. | ~av @X
### NSFW ### NSFW
Command and aliases | Description | Usage Command and aliases | Description | Usage
----------------|--------------|------- ----------------|--------------|-------
`~hentai` | 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 `~hentai` | 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
`~danbooru` | Shows a random hentai image from danbooru with a given tag. Tag is optional but preffered. (multiple tags are appended with +) | ~danbooru yuri+kissing `~danbooru` | Shows a random hentai image from danbooru with a given tag. Tag is optional but preffered. (multiple tags are appended with +) | ~danbooru yuri+kissing
@ -295,52 +302,55 @@ Command and aliases | Description | Usage
`~butts`, `~ass`, `~butt` | Real adult content. `~butts`, `~ass`, `~butt` | Real adult content.
### ClashOfClans ### ClashOfClans
Command and aliases | Description | Usage Command and aliases | Description | Usage
----------------|--------------|------- ----------------|--------------|-------
`,createwar`, `,cw` | Creates a new war by specifying a size (>10 and multiple of 5) and enemy clan name. | ,cw 15 The Enemy Clan `,createwar`, `,cw` | Creates a new war by specifying a size (>10 and multiple of 5) and enemy clan name. | ,cw 15 The Enemy Clan
`,startwar`, `,sw` | Starts a war with a given number. `,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 `,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] `,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] `,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] `,endwar`, `,ew` | Ends the war with a given index. | ,ew [war_number]
### Pokegame ### Pokegame
Command and aliases | Description | Usage 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 `>movelist`, `>ml` | Lists the moves you are able to use
`>heal` | Heals someone. Revives those that fainted. Costs a NadekoFlower | >revive @someone `>heal` | Heals someone. Revives those who fainted. Costs a NadekoFlower | >heal @someone
`>type` | Get the poketype of the target. | >type @someone `>type` | Get the poketype of the target. | >type @someone
`>settype` | Set your poketype. Costs a NadekoFlower. | >settype fire `>settype` | Set your poketype. Costs a NadekoFlower. | >settype fire
### Translator ### Translator
Command and aliases | Description | Usage Command and aliases | Description | Usage
----------------|--------------|------- ----------------|--------------|-------
`~translate`, `~trans` | Translates from>to text. From the given language to the destiation language. | ~trans en>fr Hello `~translate`, `~trans` | Translates from>to text. From the given language to the destiation language. | ~trans en>fr Hello
`~translangs` | List the valid languages for translation. `~translangs` | List the valid languages for translation.
### Customreactions ### Customreactions
Command and aliases | Description | Usage Command and aliases | Description | Usage
----------------|--------------|------- ----------------|--------------|-------
`\o\` | Custom reaction. | \o\ `\o\` | Custom reaction. | \o\
`/o/` | Custom reaction. | /o/ `/o/` | Custom reaction. | /o/
`moveto` | Custom reaction. | moveto `moveto` | Custom reaction. | moveto
`comeatmebro` | Custom reaction. | comeatmebro `comeatmebro` | Custom reaction. | comeatmebro
`e` | Custom reaction. | e `e` | Custom reaction. | e
`@BotName insult`, `<@!119777021319577610> insult` | Custom reaction. | %mention% insult `@BotName insult`, `<@!116275390695079945> insult` | Custom reaction. | %mention% insult
`@BotName praise`, `<@!119777021319577610> praise` | Custom reaction. | %mention% praise `@BotName praise`, `<@!116275390695079945> praise` | Custom reaction. | %mention% praise
`@BotName pat`, `<@!119777021319577610> pat` | Custom reaction. | %mention% pat `@BotName pat`, `<@!116275390695079945> pat` | Custom reaction. | %mention% pat
`@BotName cry`, `<@!119777021319577610> cry` | Custom reaction. | %mention% cry `@BotName cry`, `<@!116275390695079945> cry` | Custom reaction. | %mention% cry
`@BotName are you real?`, `<@!119777021319577610> are you real?` | Custom reaction. | %mention% are you real? `@BotName are you real?`, `<@!116275390695079945> are you real?` | Custom reaction. | %mention% are you real?
`@BotName are you there?`, `<@!119777021319577610> are you there?` | Custom reaction. | %mention% are you there? `@BotName are you there?`, `<@!116275390695079945> are you there?` | Custom reaction. | %mention% are you there?
`@BotName draw`, `<@!119777021319577610> draw` | Custom reaction. | %mention% draw `@BotName draw`, `<@!116275390695079945> draw` | Custom reaction. | %mention% draw
`@BotName bb`, `<@!119777021319577610> bb` | Custom reaction. | %mention% bb `@BotName bb`, `<@!116275390695079945> bb` | Custom reaction. | %mention% bb
`@BotName call`, `<@!119777021319577610> call` | Custom reaction. | %mention% call `@BotName call`, `<@!116275390695079945> call` | Custom reaction. | %mention% call
`@BotName disguise`, `<@!119777021319577610> disguise` | Custom reaction. | %mention% disguise `@BotName disguise`, `<@!116275390695079945> disguise` | Custom reaction. | %mention% disguise
`~hentai` | Custom reaction. | ~hentai
### Trello ### Trello
Command and aliases | Description | Usage Command and aliases | Description | Usage
----------------|--------------|------- ----------------|--------------|-------
`trello bind` | Bind a trello bot to a single channel. You will receive notifications from your board when something is added or edited. | bind [board_id] `trello bind` | Bind a trello bot to a single channel. You will receive notifications from your board when something is added or edited. | bind [board_id]
`trello unbind` | Unbinds a bot from the channel and board. `trello unbind` | Unbinds a bot from the channel and board.

@ -1 +1 @@
Subproject commit 80f9d6f2de25355a245bf93d4019d16e3fd033ca Subproject commit 6bfeaaddf0cbc83fe0ca44e6164f61c6f8fdaf27

View File

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