Merge pull request #501 from Kwoth/dev

0.99.9x
This commit is contained in:
Master Kwoth 2016-08-02 18:04:38 +02:00 committed by GitHub
commit 1c67d7642d
78 changed files with 938 additions and 1219 deletions

1
.gitignore vendored
View File

@ -22,6 +22,7 @@ obj/
NadekoBot/bin/debug/*.*
NadekoBot/bin/debug/data/permissions
NadekoBot/bin/debug/data/incidents
NadekoBot/bin/debug/data/musicdata
NadekoBot/bin/NadekoRelease/*.*
!NadekoBot/bin/Debug/data/currency_images/*
Tests/bin

View File

@ -1,65 +1,112 @@
________________________________________________________________________________
*Thanks to @Flatbread for making this guide*
*Thanks to @Flatbread and Mirai for making this guide*
________________________________________________________________________________
#### Setting Up NadekoBot v0.98
###### Prerequisites:
1) NET Framework 4.5.2 (or 4.6)
- Start with making a folder, lets name it `Nadeko`
- Make sure you have **7zip** installed, if not then head to http://www.7-zip.org/download.html and download/install it.
- Now head to https://github.com/Kwoth/NadekoUpdater/releases/tag/v1.0 and download `WINDOWS.-.nadeupdater.7z
- *Alternatively, you can download nadekobot from [releases](https://github.com/Kwoth/NadekoBot/releases) and extract the zip yourself. That is what updater does, except it makes it easier for you to update because it doesn't overwrite important files. If you are downloading releases you will have to be careful about your config, credentials, and other files you edited in order to preserve your data every time you update.*
### Setting Up NadekoBot on Windows
#### Prerequisites
- 1) [NET Framework][NET Framework] 4.5.2 (or 4.6)
- 2) [FFMPEG][FFMPEG]
- 3) Google Account
- 4) Soundcloud Account (if you want soundcloud support)
- 5) [7zip][7zip] (or whatever you are using, WinRar)
- 6) [Notepad++][Notepad++]
####Guide:
- Create a folder, name it `Nadeko`.
- Head to [Releases][Releases]* and download `WINDOWS.-.nadeupdater.7z`.
- Copy `WINDOWS.-.nadeupdater.7z` to the `Nadeko` (folder we created before) and extract everything.
- You will see a file `NadekoUpdater.bat ` and a folder `publish ` after extraction.
- Run/Launch/Open the file `NadekoUpdater.bat ` and you will see it running in cmd.exe asking you with **3 options** *1-3*.
- You can try the stable release, but its better to get the newest release if you want all features/upgrades. So for that press `2 ` and hit `Enter ` (read everything shows up on screen)
- It should ask you `Are you sure you want to update?` and for that type `y ` and hit `Enter `
- It should complete downloading (might take a while) and you can type `3 ` and hit `Enter ` and close it.
- You should now see a new folder `NadekoBot ` inside our `Nadeko ` folder.
- Open it and head over to https://github.com/Kwoth/NadekoBot/blob/master/README.md to setup credentials or just check it out for your knowledge.
- **For Basic Credentials Setup:**
- Rename `credentials_example.json ` into `credentials.json ` (Note: If you do not see a **.json** after `credentials_example.json `, do not add the **.json**. `You are most likely to have "Hide file extensions" as enabled. `)
- **Go to:** http://discord.kongslien.net/guide.html **for detailed guidance with screenshots.** or :arrow_down:
- **Follow for textual guidelines:** Go here https://discordapp.com/developers/applications/me
- Log in with your Discord account. Press **New Application** and fill out an **App Name** and, optionally, an app description and icon. Afterwards, create the application. Once the application is created, click on **Create a Bot User** and confirm it. You will then see the bot's username, ID and token. Reveal and copy the **token** and the **bot ID** *(one by one xD)*.
- Open up `credentials.json` with **NotePad++** Paste the **token** into the **Token** field, between the `"quotes"`. Paste the **Bot ID** into the **BotID** field, when done, *Save* and *close* `credentials.json`
- **To Invite your bot to your server:**
- Copy your CLIENT ID (that's in the same Developer page where you brought your token) and replace `12345678` in this link:
`https://discordapp.com/oauth2/authorize?client_id=12345678&scope=bot&permissions=66186303 ` with it. Go to that link and you will be able to add your bot to your server.
- Start NadekoBot.exe. In a text channel, **not a direct message**, type in [.uid @______] without the brackets, filling in the underlined portion with your name and send the message. Your bot will reply with a number; this is your ID. Copy this ID and close NadekoBot.exe.
- Reopen credentials.json. Paste your ID into the square brackets ("OwnerIds": [1231312313]). **Just paste/replace your ID with existing and keep the default format intact, you don't need to add extra space or anything else.** You can add multiple owners by separating IDs with a comma. Close and save credentials.json.
- 1) Stable release - current stable release, but might not contain all the newest Nadeko updates.
- 2) Newest release - release with all features/upgrades.
- 3) Exit
- Press `2` on your keyboard and hit `Enter`. Type `y` and hit `Enter` again. Downloading might take a while, so just be patient and wait. When download is done, press `3` on your keyboard and close the updater.
- You should have a new folder named `NadekoBot` inside the `Nadeko` folder we previously created.
####Creating DiscordBot application
- Go to [DiscordApp][DiscordApp].
- Log in with your Discord account.
- On the left side, press `New Application`.
- Fill out the `App Name` (your bot's name, in this case), put the image you want, and add an app description(optional).
- Create the application.
- Once the application is created, click on `Create a Bot User` and confirm it.
- Keep this window open for now.
####Setting up Credentials.json file
- In our `NadekoBot` folder you should have `.json` file named `credentials_example.json`. (Note: If you do not see a **.json** after `credentials_example.json `, do not add the `**.json**`. You most likely have `"Hide file extensions"` enabled.)
- Rename `credentials_example.json` to `credentials.json`.
- Open the file with your [Notepad++][Notepad++].
- In there you will see fields like `Token`, `ClientId`, `BotId`, `OwnerIDs`.
- In your [DiscordApp][DiscordApp], under `Bot User` part, you will see the `Token:click to reveal` part, click to reveal it.
- Copy your bot's token, and put it between `" "` in your `credentials.json` file.
- Copy `Client ID` and replace it with the example one in your `credentials.json`.
- Copy `Bot ID` and replace it with the example one in your `credentials.json`.
- Save your `credentials.json` but keep it open. We need to put your `User ID` and owner.
####Inviting your bot to your server [Invite Guide][Invite Guide]
- Create a new server in Discord.
- Copy your `Client ID` from your [DiscordApp][DiscordApp].
- Replace `12345678` in this link `https://discordapp.com/oauth2/authorize?client_id=12345678&scope=bot&permissions=66186303` with your `Client ID`.
- Link should look like this: `https://discordapp.com/oauth2/authorize?client_id=**YOUR_CLENT_ID**&scope=bot&permissions=66186303`.
- Go to newly created link and pick the server we created, and click `Authorize`.
- Bot should be added to your server.
####Starting the bot
- Enter your `NadekoBot` folder that should be (hopefully) in your `Nadeko` folder.
- Run `NadekoBot.exe` (Note: There is `NadekoBot.exe` and `NadekoBot.exe.config`, dont run the second one)
- Your bot should now be online in the server we added him to.
- Note: Your bot will be offline in case you close `NadekoBot.exe`.
####Setting up OwnerIds:
- In the server where your bot is, in a text channel, type `.uid`
- Your `User ID` should show, copy it.
- Close `NadekoBot.exe`
- Replace your `User ID` in the `credentials.json` between `[ ]` and save the changes.
- Run `NadekoBot.exe` again.
- Now you are the bot owner.
- You can add `User IDs` from the other users by separating IDs with a comma if you want to have more owners.
`*Alternatively, you can download nadekobot from [Releases][Releases] and extract the zip yourself. That is what updater does, except it makes it easier for you to update because it doesn't overwrite important files. If you are downloading releases you will have to be careful about your config, credentials, and other files you edited in order to preserve your data every time you update.`
________________________________________________________________________________
#### Setting Up NadekoBot For Music
###### Setting up `ffmpeg` with installer:
1) Google Account
2) Soundcloud Account (if you want soundcloud support)
3) Download installer here: https://goo.gl/lQZnsH (pick the one for your system, either 32 or 64bit and then click 'download')
4) Run the installer
##### Prerequisites
- 1) [FFMPEG][FFMPEG] installed.
- 2) Setting up API keys.
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.
- Follow these steps on how to setup Google API keys:
- Go to [Google Console][Google Console] 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` and `Custom Search Api`. Under the `YouTube APIs` section, enable `YouTube Data API`.
- On the left tab, access `Credentials`. Click `Create Credentials` button. 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 we copied.
- Follow these steps on how to setup Soundcloud API key:
- Go to [Soundcloud][Soundcloud].
- Enter a name for the app and create it.
- You will see a page with the title of your app, and a field labeled `Client ID`. Copy the ID.
- In `credentials.json`, fill in `"SoundcloudClientID"` with the copied ID.
- Restart your computer.
###### Prerequisites for manual `ffmpeg` setup:
1) Google Account
2) Soundcloud Account (if you want soundcloud support)
##### Prerequisites for manual `ffmpeg` setup:
**Do this step in case you were not able to install `ffmpeg` with the installer.**
- Create a folder named `ffmpeg` in your main Windows directory. We will use **C:\ffmpeg** (for our guide)
- Download FFMPEG through the link https://ffmpeg.zeranoe.com/builds/ (download static build)
- Extract it using `7zip` and place the folder `ffmpeg-xxxxx-git-xxxxx-xxxx-static` inside **C:\ffmpeg**
- Before proceeding, check out this gif to set up `ffmpeg` PATH correctly http://i.imgur.com/aR5l1Hn.gif *(thanks to PooPeePants#7135)*
- Go to My Computer, right click and select Properties. On the left tab, select Advanced System Settings. Under the Advanced tab, select Environmental Variables near the bottom. One of the variables should be called "Path". Add a semi-colon (;) to the end followed by your FFMPEG's **bin** install location (**for example C:\ffmpeg\ffmpeg-xxxxx-git-xxxxx-xxxx-static\bin**). Save and close.
- 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.
- Setup your API keys as explained above.
- Restart your computer.
[NET Framework]: https://www.microsoft.com/en-us/download/details.aspx?id=48130
[FFMPEG]: https://github.com/Soundofdarkness/FFMPEG-Installer
[7zip]: http://www.7-zip.org/download.html
[Releases]: //github.com/Kwoth/NadekoUpdater/releases/tag/v1.0
[DiscordApp]: https://discordapp.com/developers/applications/me
[Notepad++]: https://notepad-plus-plus.org/
[Invite Guide]: http://discord.kongslien.net/guide.html
[Google Console]: https://console.developers.google.com
[Soundcloud]: https://soundcloud.com/you/apps/new

54
DockerGuide.md Normal file
View File

@ -0,0 +1,54 @@
## Docker guide with digitalocean
#####Prerequisites:
- Digital ocean account (you can use my [reflink][reflink] to support the project and get 10$ after you register)
- [PuTTY][PuTTY]
- A bot account - follow this [guide][guide]
- $5
- Common sense
#####Guide
- Click on the create droplet button
![img](http://i.imgur.com/g2ayOcC.png)
- Pick one click apps and select docker on 14.04
![img](http://imgur.com/065Xkme.png)
- Pick any droplet size you want (5$ will work ok-ish on a few servers)
- Pick location closest to your discord server's location
- Pick a hostname
![img](http://imgur.com/ifPKB6p.png)
- Click create
You will get an email from DigitalOcean with your credentials now.
Open putty and type ip adress **you got in your email** with port 22
![img](http://imgur.com/Mh5ehsh.png)
- Console will open and you will be prompted for a username, type `root`.
- Type in the password you got in the email.
- Confirm the password you just typed in.
- Type in the new password.
- Confirm new password.
- When you are successfully logged in, type
`docker run --name nadeko -v /nadeko:/config uirel/nadeko`
- Wait for it to download and at one point it is going to start throwing errors due to `credentials.json` being empty
- CTRL+C to exit that
- Type `docker stop nadeko`
- Type `nano /nadeko/credentials.json` and type in your `credentials`
- CTRL+X then CTRL+Y to save
- Type `docker start nadeko`
- Type `docker logs -f nadeko` to see the console output
**Your bot is running, enjoy! o/**
*When you want to update the bot, just type `docker restart nadeko` as it always downloads latest prerelease*
[reflink]: http://m.do.co/c/46b4d3d44795/
[PuTTY]: http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html
[guide]: http://discord.kongslien.net/guide.html

View File

@ -26,10 +26,12 @@ If you entered your Droplets IP address correctly, it should show **login as:**
######MONO (Source: [Mono Source][Mono Source])
**1)**
**1) Installing Mono**
`sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF`
`echo "deb http://download.mono-project.com/repo/debian wheezy main" | sudo tee /etc/apt/sources.list.d/mono-xamarin.list`
`sudo apt-get update`
Note if the command is not being initiated, hit **Enter**
@ -47,7 +49,9 @@ Note if the command is not being initiated, hit **Enter**
*ONLY CentOS 7, Fedora 19 (and later)*
`yum install yum-util`
`rpm --import "http://keyserver.ubuntu.com/pks/lookup?op=get&search=0x3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF"`
`yum-config-manager --add-repo http://download.mono-project.com/repo/centos/`
**3)**
@ -71,8 +75,11 @@ Opus Voice Codec
**In case you are having issues with Mono where you get a random string and the bot won't run, do this:**
`sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF`
`echo "deb http://download.mono-project.com/repo/debian wheezy main" | sudo tee /etc/apt/sources.list.d/mono-xamarin.list`
`apt-get install ca-certificates-mono`
`mozroots --import --sync`
@ -222,6 +229,8 @@ Type/ Copy and hit **Enter**.
Now time to **move bot to background** and to do that, press **CTRL+B+D** (this will ditach the nadeko session using TMUX), and you can finally close PuTTY now.
Copy your CLIENT ID (that's in the same Developer page where you brought your token) and replace `12345678` in this link: `https://discordapp.com/oauth2/authorize?client_id=12345678&scope=bot&permissions=66186303` with it. Go to that link and you will be able to add your bot to your server.
**NOW YOU HAVE YOUR OWN NADEKO BOT** `Thanks to Kwoth <3`
######SOME MORE INFO (JUST TO KNOW):

View File

@ -13,129 +13,74 @@ namespace NadekoBot.Classes
private string FilePath { get; } = "data/nadekobot.sqlite";
public SQLiteConnection Connection { get; set; }
static DbHandler() { }
public DbHandler()
{
using (var conn = new SQLiteConnection(FilePath))
Connection = new SQLiteConnection(FilePath);
Connection.CreateTable<Stats>();
Connection.CreateTable<Command>();
Connection.CreateTable<Announcement>();
Connection.CreateTable<Request>();
Connection.CreateTable<TypingArticle>();
Connection.CreateTable<CurrencyState>();
Connection.CreateTable<CurrencyTransaction>();
Connection.CreateTable<Donator>();
Connection.CreateTable<UserPokeTypes>();
Connection.CreateTable<UserQuote>();
Connection.CreateTable<Reminder>();
Connection.CreateTable<SongInfo>();
Connection.CreateTable<PlaylistSongInfo>();
Connection.CreateTable<MusicPlaylist>();
Connection.CreateTable<Incident>();
Connection.Execute(Queries.TransactionTriggerQuery);
try
{
conn.CreateTable<Stats>();
conn.CreateTable<Command>();
conn.CreateTable<Announcement>();
conn.CreateTable<Request>();
conn.CreateTable<TypingArticle>();
conn.CreateTable<CurrencyState>();
conn.CreateTable<CurrencyTransaction>();
conn.CreateTable<Donator>();
conn.CreateTable<UserPokeTypes>();
conn.CreateTable<UserQuote>();
conn.CreateTable<Reminder>();
conn.CreateTable<SongInfo>();
conn.CreateTable<PlaylistSongInfo>();
conn.CreateTable<MusicPlaylist>();
conn.CreateTable<Incident>();
conn.Execute(Queries.TransactionTriggerQuery);
try
{
conn.Execute(Queries.DeletePlaylistTriggerQuery);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
Connection.Execute(Queries.DeletePlaylistTriggerQuery);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
internal T FindOne<T>(Expression<Func<T, bool>> p) where T : IDataModel, new()
{
using (var conn = new SQLiteConnection(FilePath))
{
return conn.Table<T>().Where(p).FirstOrDefault();
}
return Connection.Table<T>().Where(p).FirstOrDefault();
}
internal IList<T> FindAll<T>(Expression<Func<T, bool>> p) where T : IDataModel, new()
{
using (var conn = new SQLiteConnection(FilePath))
{
return conn.Table<T>().Where(p).ToList();
}
}
internal void DeleteAll<T>() where T : IDataModel
{
using (var conn = new SQLiteConnection(FilePath))
{
conn.DeleteAll<T>();
}
return Connection.Table<T>().Where(p).ToList();
}
internal void DeleteWhere<T>(Expression<Func<T, bool>> p) where T : IDataModel, new()
{
using (var conn = new SQLiteConnection(FilePath))
{
var id = conn.Table<T>().Where(p).FirstOrDefault()?.Id;
if (id.HasValue)
conn.Delete<T>(id);
}
}
internal void InsertData<T>(T o) where T : IDataModel
{
using (var conn = new SQLiteConnection(FilePath))
{
conn.Insert(o, typeof(T));
}
}
internal void InsertMany<T>(T objects) where T : IEnumerable<IDataModel>
{
using (var conn = new SQLiteConnection(FilePath))
{
conn.InsertAll(objects);
}
}
internal void UpdateData<T>(T o) where T : IDataModel
{
using (var conn = new SQLiteConnection(FilePath))
{
conn.Update(o, typeof(T));
}
}
internal void UpdateAll<T>(IEnumerable<T> objs) where T : IDataModel
{
using (var conn = new SQLiteConnection(FilePath))
{
conn.UpdateAll(objs);
}
var id = Connection.Table<T>().Where(p).FirstOrDefault()?.Id;
if (id.HasValue)
Connection.Delete<T>(id);
}
internal HashSet<T> GetAllRows<T>() where T : IDataModel, new()
{
using (var conn = new SQLiteConnection(FilePath))
{
return new HashSet<T>(conn.Table<T>());
}
return new HashSet<T>(Connection.Table<T>());
}
internal CurrencyState GetStateByUserId(long id)
{
using (var conn = new SQLiteConnection(FilePath))
{
return conn.Table<CurrencyState>().Where(x => x.UserId == id).FirstOrDefault();
}
return Connection.Table<CurrencyState>().Where(x => x.UserId == id).FirstOrDefault();
}
internal T Delete<T>(int id) where T : IDataModel, new()
{
using (var conn = new SQLiteConnection(FilePath))
{
var found = conn.Find<T>(id);
if (found != null)
conn.Delete<T>(found.Id);
return found;
}
var found = Connection.Find<T>(id);
if (found != null)
Connection.Delete<T>(found.Id);
return found;
}
/// <summary>
@ -143,14 +88,11 @@ namespace NadekoBot.Classes
/// </summary>
internal void Save<T>(T o) where T : IDataModel, new()
{
using (var conn = new SQLiteConnection(FilePath))
{
var found = conn.Find<T>(o.Id);
if (found == null)
conn.Insert(o, typeof(T));
else
conn.Update(o, typeof(T));
}
var found = Connection.Find<T>(o.Id);
if (found == null)
Connection.Insert(o, typeof(T));
else
Connection.Update(o, typeof(T));
}
/// <summary>
@ -158,20 +100,14 @@ namespace NadekoBot.Classes
/// </summary>
internal void SaveAll<T>(IEnumerable<T> ocol) where T : IDataModel, new()
{
using (var conn = new SQLiteConnection(FilePath))
{
foreach (var o in ocol)
conn.InsertOrReplace(o);
}
foreach (var o in ocol)
Connection.InsertOrReplace(o);
}
internal T GetRandom<T>(Expression<Func<T, bool>> p) where T : IDataModel, new()
{
using (var conn = new SQLiteConnection(FilePath))
{
var r = new Random();
return conn.Table<T>().Where(p).ToList().OrderBy(x => r.Next()).FirstOrDefault();
}
var r = new Random();
return Connection.Table<T>().Where(p).ToList().OrderBy(x => r.Next()).FirstOrDefault();
}
/// <summary>
///
@ -180,24 +116,19 @@ namespace NadekoBot.Classes
/// <returns></returns>
internal List<PlaylistData> GetPlaylistData(int num)
{
using (var conn = new SQLiteConnection(FilePath))
{
return conn.Query<PlaylistData>(
return Connection.Query<PlaylistData>(
@"SELECT mp.Name as 'Name',mp.Id as 'Id', mp.CreatorName as 'Creator', Count(*) as 'SongCnt' FROM MusicPlaylist as mp
INNER JOIN PlaylistSongInfo as psi
ON mp.Id = psi.PlaylistId
Group BY mp.Name
Order By mp.DateAdded desc
Limit 20 OFFSET ?", num * 20);
}
}
internal IEnumerable<CurrencyState> GetTopRichest(int n = 10)
{
using (var conn = new SQLiteConnection(FilePath))
{
return conn.Table<CurrencyState>().OrderByDescending(cs => cs.Value).Take(n).ToList();
}
return Connection.Table<CurrencyState>().OrderByDescending(cs => cs.Value).Take(n).ToList();
}
}
}

View File

@ -10,7 +10,7 @@ namespace NadekoBot.Classes
return;
await Task.Run(() =>
{
DbHandler.Instance.InsertData(new DataModels.CurrencyTransaction
DbHandler.Instance.Connection.Insert(new DataModels.CurrencyTransaction
{
Reason = reason,
UserId = (long)u.Id,
@ -36,7 +36,7 @@ namespace NadekoBot.Classes
if (state.Value < amount)
return false;
DbHandler.Instance.InsertData(new DataModels.CurrencyTransaction
DbHandler.Instance.Connection.Insert(new DataModels.CurrencyTransaction
{
Reason = reason,
UserId = (long)u.Id,

View File

@ -19,7 +19,7 @@ namespace NadekoBot.Classes
Read = false
};
DbHandler.Instance.InsertData<Incident>(incident);
DbHandler.Instance.Connection.Insert(incident, typeof(Incident));
}
}
}

View File

@ -46,20 +46,7 @@ namespace NadekoBot
commandService.CommandExecuted += StatsCollector_RanCommand;
commandService.CommandFinished += CommandService_CommandFinished;
commandService.CommandErrored += (s, e) =>
{
try
{
if (e.ErrorType == CommandErrorType.Exception)
File.AppendAllText("errors.txt", $@"Command: {e.Command}
{e.Exception}
-------------------------------------
");
}
catch {
Console.WriteLine("Command errored errorring");
}
};
commandService.CommandErrored += CommandService_CommandFinished;
Task.Run(StartCollecting);
@ -208,7 +195,7 @@ namespace NadekoBot
.ConfigureAwait(false);
var connectedServers = NadekoBot.Client.Servers.Count();
Classes.DbHandler.Instance.InsertData(new DataModels.Stats
Classes.DbHandler.Instance.Connection.Insert(new DataModels.Stats
{
OnlineUsers = onlineUsers,
RealOnlineUsers = realOnlineUsers,
@ -236,10 +223,31 @@ namespace NadekoBot
private void CommandService_CommandFinished(object sender, CommandEventArgs e)
{
DateTime dt;
if (!commandTracker.TryGetValue(e.Message.Id, out dt))
return;
Console.WriteLine($">>COMMAND ENDED after *{(DateTime.UtcNow - dt).TotalSeconds}s*\nCmd: {e.Command.Text}\nMsg: {e.Message.Text}\nUsr: {e.User.Name} [{e.User.Id}]\nSrvr: {e.Server?.Name ?? "PRIVATE"} [{e.Server?.Id}]\n-----");
try
{
if (e is CommandErrorEventArgs)
{
var er = e as CommandErrorEventArgs;
if (er.ErrorType == CommandErrorType.Exception)
{
File.AppendAllText("errors.txt", $@"Command: {er.Command}
{er.Exception}
-------------------------------------
");
Console.WriteLine($">>COMMAND ERRORED after *{(DateTime.UtcNow - dt).TotalSeconds}s*\nCmd: {e.Command.Text}\nMsg: {e.Message.Text}\nUsr: {e.User.Name} [{e.User.Id}]\nSrvr: {e.Server?.Name ?? "PRIVATE"} [{e.Server?.Id}]\n-----");
}
}
else
{
Console.WriteLine($">>COMMAND ENDED after *{(DateTime.UtcNow - dt).TotalSeconds}s*\nCmd: {e.Command.Text}\nMsg: {e.Message.Text}\nUsr: {e.User.Name} [{e.User.Id}]\nSrvr: {e.Server?.Name ?? "PRIVATE"} [{e.Server?.Id}]\n-----");
}
}
catch { }
}
private async void StatsCollector_RanCommand(object sender, CommandEventArgs e)
@ -252,7 +260,7 @@ namespace NadekoBot
try
{
commandsRan++;
Classes.DbHandler.Instance.InsertData(new DataModels.Command
Classes.DbHandler.Instance.Connection.Insert(new DataModels.Command
{
ServerId = (long)(e.Server?.Id ?? 0),
ServerName = e.Server?.Name ?? "--Direct Message--",

View File

@ -25,16 +25,13 @@ namespace NadekoBot.Classes
{
private static DateTime lastRefreshed = DateTime.MinValue;
private static string token { get; set; } = "";
private static readonly HttpClient httpClient = new HttpClient();
public static async Task<Stream> GetResponseStreamAsync(string url,
IEnumerable<KeyValuePair<string, string>> headers = null, RequestHttpMethod method = RequestHttpMethod.Get)
{
if (string.IsNullOrWhiteSpace(url))
throw new ArgumentNullException(nameof(url));
//if its a post or there are no headers, use static httpclient
// if there are headers and it's get, it's not threadsafe
var cl = headers == null || method == RequestHttpMethod.Post ? httpClient : new HttpClient();
var cl = new HttpClient();
cl.DefaultRequestHeaders.Clear();
switch (method)
{
@ -178,7 +175,7 @@ namespace NadekoBot.Classes
return null;
}
public static async Task<string> GetRelatedVideoId(string id)
public static async Task<IEnumerable<string>> GetRelatedVideoIds(string id, int count = 1)
{
if (string.IsNullOrWhiteSpace(id))
throw new ArgumentNullException(nameof(id));
@ -189,20 +186,14 @@ namespace NadekoBot.Classes
}
var response = await GetResponseStringAsync(
$"https://www.googleapis.com/youtube/v3/search?" +
$"part=snippet&maxResults=1&type=video" +
$"part=snippet&maxResults={count}&type=video" +
$"&relatedToVideoId={id}" +
$"&key={NadekoBot.Creds.GoogleAPIKey}").ConfigureAwait(false);
JObject obj = JObject.Parse(response);
var data = JsonConvert.DeserializeObject<YoutubeVideoSearch>(response);
if (data.items.Length > 0)
{
var toReturn = "http://www.youtube.com/watch?v=" + data.items[0].id.videoId.ToString();
return toReturn;
}
else
return null;
return data.items.Select(v => "http://www.youtube.com/watch?v=" + v.id.videoId);
}
public static async Task<string> GetPlaylistIdByKeyword(string query)

View File

@ -64,7 +64,7 @@ namespace NadekoBot.Modules.Administration
commands.ForEach(cmd => cmd.Init(cgb));
cgb.CreateCommand(Prefix + "delmsgoncmd")
.Description("Toggles the automatic deletion of user's successful command message to prevent chat flood. Server Manager Only.")
.Description($"Toggles the automatic deletion of user's successful command message to prevent chat flood. **Server Manager Only.** | `{Prefix}delmsgoncmd`")
.AddCheck(SimpleCheckers.ManageServer())
.Do(async e =>
{
@ -79,7 +79,7 @@ namespace NadekoBot.Modules.Administration
});
cgb.CreateCommand(Prefix + "restart")
.Description("Restarts the bot. Might not work. **Bot Owner Only**")
.Description($"Restarts the bot. Might not work. **Bot Owner Only** | `{Prefix}restart`")
.AddCheck(SimpleCheckers.OwnerOnly())
.Do(async e =>
{
@ -90,7 +90,7 @@ namespace NadekoBot.Modules.Administration
});
cgb.CreateCommand(Prefix + "setrole").Alias(Prefix + "sr")
.Description($"Sets a role for a given user. | `{Prefix}sr @User Guest`")
.Description($"Sets a role for a given user. **Needs Manage Roles Permissions.**| `{Prefix}sr @User Guest`")
.Parameter("user_name", ParameterType.Required)
.Parameter("role_name", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.CanManageRoles)
@ -133,7 +133,7 @@ namespace NadekoBot.Modules.Administration
});
cgb.CreateCommand(Prefix + "removerole").Alias(Prefix + "rr")
.Description($"Removes a role from a given user. | `{Prefix}rr @User Admin`")
.Description($"Removes a role from a given user. **Needs Manage Roles Permissions.**| `{Prefix}rr @User Admin`")
.Parameter("user_name", ParameterType.Required)
.Parameter("role_name", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.CanManageRoles)
@ -171,7 +171,7 @@ namespace NadekoBot.Modules.Administration
cgb.CreateCommand(Prefix + "renamerole")
.Alias(Prefix + "renr")
.Description($"Renames a role. Role you are renaming must be lower than bot's highest role. | `{Prefix}renr \"First role\" SecondRole`")
.Description($"Renames a role. Roles you are renaming must be lower than bot's highest role. **Manage Roles Permissions.** | `{Prefix}renr \"First role\" SecondRole`")
.Parameter("r1", ParameterType.Required)
.Parameter("r2", ParameterType.Required)
.AddCheck(new SimpleCheckers.ManageRoles())
@ -204,7 +204,7 @@ namespace NadekoBot.Modules.Administration
});
cgb.CreateCommand(Prefix + "removeallroles").Alias(Prefix + "rar")
.Description($"Removes all roles from a mentioned user. | `{Prefix}rar @User`")
.Description($"Removes all roles from a mentioned user. **Needs Manage Roles Permissions.**| `{Prefix}rar @User`")
.Parameter("user_name", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.CanManageRoles)
.Do(async e =>
@ -230,7 +230,7 @@ namespace NadekoBot.Modules.Administration
});
cgb.CreateCommand(Prefix + "createrole").Alias(Prefix + "cr")
.Description($"Creates a role with a given name. | `{Prefix}cr Awesome Role`")
.Description($"Creates a role with a given name. **Needs Manage Roles Permissions.**| `{Prefix}cr Awesome Role`")
.Parameter("role_name", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.CanManageRoles)
.Do(async e =>
@ -253,7 +253,7 @@ namespace NadekoBot.Modules.Administration
.Parameter("r", ParameterType.Optional)
.Parameter("g", ParameterType.Optional)
.Parameter("b", ParameterType.Optional)
.Description($"Set a role's color to the hex or 0-255 rgb color value provided. | `{Prefix}rc Admin 255 200 100` or `{Prefix}rc Admin ffba55`")
.Description($"Set a role's color to the hex or 0-255 rgb color value provided. **Needs Manage Roles Permissions.** | `{Prefix}rc Admin 255 200 100` or `{Prefix}rc Admin ffba55`")
.Do(async e =>
{
if (!e.User.ServerPermissions.ManageRoles)
@ -298,7 +298,7 @@ namespace NadekoBot.Modules.Administration
cgb.CreateCommand(Prefix + "ban").Alias(Prefix + "b")
.Parameter("user", ParameterType.Required)
.Parameter("msg", ParameterType.Unparsed)
.Description($"Bans a user by id or name with an optional message. | `{Prefix}b \"@some Guy\" Your behaviour is toxic.`")
.Description($"Bans a user by id or name with an optional message. **Needs Ban Permissions.**| `{Prefix}b \"@some Guy\" Your behaviour is toxic.`")
.Do(async e =>
{
var msg = e.GetArg("msg");
@ -333,7 +333,7 @@ namespace NadekoBot.Modules.Administration
cgb.CreateCommand(Prefix + "softban").Alias(Prefix + "sb")
.Parameter("user", ParameterType.Required)
.Parameter("msg", ParameterType.Unparsed)
.Description($"Bans and then unbans a user by id or name with an optional message. | `{Prefix}sb \"@some Guy\" Your behaviour is toxic.`")
.Description($"Bans and then unbans a user by id or name with an optional message. **Needs Ban Permissions.**| `{Prefix}sb \"@some Guy\" Your behaviour is toxic.`")
.Do(async e =>
{
var msg = e.GetArg("msg");
@ -369,7 +369,7 @@ namespace NadekoBot.Modules.Administration
cgb.CreateCommand(Prefix + "kick").Alias(Prefix + "k")
.Parameter("user")
.Parameter("msg", ParameterType.Unparsed)
.Description($"Kicks a mentioned user. | `{Prefix}k \"@some Guy\" Your behaviour is toxic.`")
.Description($"Kicks a mentioned user. **Needs Kick Permissions.**| `{Prefix}k \"@some Guy\" Your behaviour is toxic.`")
.Do(async e =>
{
var msg = e.GetArg("msg");
@ -400,13 +400,13 @@ namespace NadekoBot.Modules.Administration
}
});
cgb.CreateCommand(Prefix + "mute")
.Description($"Mutes mentioned user or users. | `{Prefix}mute \"@Someguy\"` or `{Prefix}mute \"@Someguy\" \"@Someguy\"`")
.Description($"Mutes mentioned user or users. **Needs Mute Permissions.**| `{Prefix}mute \"@Someguy\"` or `{Prefix}mute \"@Someguy\" \"@Someguy\"`")
.Parameter("throwaway", ParameterType.Unparsed)
.Do(async e =>
{
if (!e.User.ServerPermissions.MuteMembers)
{
await e.Channel.SendMessage("You do not have permission to do that.").ConfigureAwait(false);
await e.Channel.SendMessage("I most likely don't have the permission necessary for that.").ConfigureAwait(false);
return;
}
if (!e.Message.MentionedUsers.Any())
@ -421,12 +421,12 @@ namespace NadekoBot.Modules.Administration
}
catch
{
await e.Channel.SendMessage("I do not have permission to do that most likely.").ConfigureAwait(false);
await e.Channel.SendMessage("I most likely don't have the permission necessary for that.").ConfigureAwait(false);
}
});
cgb.CreateCommand(Prefix + "unmute")
.Description($"Unmutes mentioned user or users. | `{Prefix}unmute \"@Someguy\"` or `{Prefix}unmute \"@Someguy\" \"@Someguy\"`")
.Description($"Unmutes mentioned user or users. **Needs Mute Permissions.**| `{Prefix}unmute \"@Someguy\"` or `{Prefix}unmute \"@Someguy\" \"@Someguy\"`")
.Parameter("throwaway", ParameterType.Unparsed)
.Do(async e =>
{
@ -447,13 +447,13 @@ namespace NadekoBot.Modules.Administration
}
catch
{
await e.Channel.SendMessage("I do not have permission to do that most likely.").ConfigureAwait(false);
await e.Channel.SendMessage("I most likely don't have the permission necessary for that.").ConfigureAwait(false);
}
});
cgb.CreateCommand(Prefix + "deafen")
.Alias(Prefix + "deaf")
.Description($"Deafens mentioned user or users | `{Prefix}deaf \"@Someguy\"` or `{Prefix}deaf \"@Someguy\" \"@Someguy\"`")
.Description($"Deafens mentioned user or users. **Needs Deafen Permissions.**| `{Prefix}deaf \"@Someguy\"` or `{Prefix}deaf \"@Someguy\" \"@Someguy\"`")
.Parameter("throwaway", ParameterType.Unparsed)
.Do(async e =>
{
@ -474,13 +474,13 @@ namespace NadekoBot.Modules.Administration
}
catch
{
await e.Channel.SendMessage("I do not have permission to do that most likely.").ConfigureAwait(false);
await e.Channel.SendMessage("I most likely don't have the permission necessary for that.").ConfigureAwait(false);
}
});
cgb.CreateCommand(Prefix + "undeafen")
.Alias(Prefix + "undef")
.Description($"Undeafens mentioned user or users | `{Prefix}undef \"@Someguy\"` or `{Prefix}undef \"@Someguy\" \"@Someguy\"`")
.Description($"Undeafens mentioned user or users. **Needs Deafen Permissions.** | `{Prefix}undef \"@Someguy\"` or `{Prefix}undef \"@Someguy\" \"@Someguy\"`")
.Parameter("throwaway", ParameterType.Unparsed)
.Do(async e =>
{
@ -501,13 +501,13 @@ namespace NadekoBot.Modules.Administration
}
catch
{
await e.Channel.SendMessage("I do not have permission to do that most likely.").ConfigureAwait(false);
await e.Channel.SendMessage("I most likely don't have the permission necessary for that.").ConfigureAwait(false);
}
});
cgb.CreateCommand(Prefix + "delvoichanl")
.Alias(Prefix + "dvch")
.Description($"Deletes a voice channel with a given name. | `{Prefix}dvch VoiceChannelName`")
.Description($"Deletes a voice channel with a given name. **Needs Manage Channel Permissions.**| `{Prefix}dvch VoiceChannelName`")
.Parameter("channel_name", ParameterType.Required)
.Do(async e =>
{
@ -530,7 +530,7 @@ namespace NadekoBot.Modules.Administration
cgb.CreateCommand(Prefix + "creatvoichanl")
.Alias(Prefix + "cvch")
.Description($"Creates a new voice channel with a given name. | `{Prefix}cvch VoiceChannelName`")
.Description($"Creates a new voice channel with a given name. **Needs Manage Channel Permissions.** | `{Prefix}cvch VoiceChannelName`")
.Parameter("channel_name", ParameterType.Required)
.Do(async e =>
{
@ -550,7 +550,7 @@ namespace NadekoBot.Modules.Administration
cgb.CreateCommand(Prefix + "deltxtchanl")
.Alias(Prefix + "dtch")
.Description($"Deletes a text channel with a given name. | `{Prefix}dtch TextChannelName`")
.Description($"Deletes a text channel with a given name. **Needs Manage Channel Permissions.** | `{Prefix}dtch TextChannelName`")
.Parameter("channel_name", ParameterType.Required)
.Do(async e =>
{
@ -572,7 +572,7 @@ namespace NadekoBot.Modules.Administration
cgb.CreateCommand(Prefix + "creatxtchanl")
.Alias(Prefix + "ctch")
.Description($"Creates a new text channel with a given name. | `{Prefix}ctch TextChannelName`")
.Description($"Creates a new text channel with a given name. **Needs Manage Channel Permissions.** | `{Prefix}ctch TextChannelName`")
.Parameter("channel_name", ParameterType.Required)
.Do(async e =>
{
@ -592,7 +592,7 @@ namespace NadekoBot.Modules.Administration
cgb.CreateCommand(Prefix + "settopic")
.Alias(Prefix + "st")
.Description($"Sets a topic on the current channel. | `{Prefix}st My new topic`")
.Description($"Sets a topic on the current channel. **Needs Manage Channel Permissions.** | `{Prefix}st My new topic`")
.AddCheck(SimpleCheckers.ManageChannels())
.Parameter("topic", ParameterType.Unparsed)
.Do(async e =>
@ -604,7 +604,7 @@ namespace NadekoBot.Modules.Administration
cgb.CreateCommand(Prefix + "setchanlname")
.Alias(Prefix + "schn")
.Description($"Changed the name of the current channel.| `{Prefix}schn NewName`")
.Description($"Changed the name of the current channel. **Needs Manage Channel Permissions.**| `{Prefix}schn NewName`")
.AddCheck(SimpleCheckers.ManageChannels())
.Parameter("name", ParameterType.Unparsed)
.Do(async e =>
@ -617,7 +617,7 @@ namespace NadekoBot.Modules.Administration
});
cgb.CreateCommand(Prefix + "heap")
.Description("Shows allocated memory - **Bot Owner Only!**")
.Description($"Shows allocated memory - **Bot Owner Only!** | `{Prefix}heap`")
.AddCheck(SimpleCheckers.OwnerOnly())
.Do(async e =>
{
@ -628,19 +628,19 @@ namespace NadekoBot.Modules.Administration
cgb.CreateCommand(Prefix + "prune")
.Alias(Prefix + "clr")
.Description(
"`.prune` removes all nadeko's messages in the last 100 messages.`.prune X` removes last X messages from the channel (up to 100)`.prune @Someone` removes all Someone's messages in the last 100 messages.`.prune @Someone X` removes last X 'Someone's' messages in the channel. | `.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. " +
$"| `{Prefix}prune` or `{Prefix}prune 5` or `{Prefix}prune @Someone` or `{Prefix}prune @Someone X`")
.Parameter("user_or_num", ParameterType.Optional)
.Parameter("num", ParameterType.Optional)
.Do(async e =>
{
Message[] msgs;
if (string.IsNullOrWhiteSpace(e.GetArg("user_or_num"))) // if nothing is set, clear nadeko's messages, no permissions required
{
msgs = (await e.Channel.DownloadMessages(100).ConfigureAwait(false));//.Where(m => m.User.Id == e.Server.CurrentUser.Id).ToArray();
msgs = msgs.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)?.ToArray();
if (msgs == null || !msgs.Any())
return;
await e.Channel.DeleteMessages(msgs).ConfigureAwait(false);
var toDelete = msgs as Message[] ?? msgs.ToArray();
await e.Channel.DeleteMessages(toDelete).ConfigureAwait(false);
return;
}
if (!e.User.GetPermissions(e.Channel).ManageMessages)
@ -667,14 +667,14 @@ namespace NadekoBot.Modules.Administration
val = 100;
if (!int.TryParse(e.GetArg("num"), out val))
val = 100;
msgs = (await e.Channel.DownloadMessages(100).ConfigureAwait(false)).Where(m => m.User.Id == usr.Id).Take(val).ToArray();
if (!msgs.Any())
var mesgs = (await e.Channel.DownloadMessages(100).ConfigureAwait(false)).Where(m => m.User?.Id == usr.Id).Take(val);
if (mesgs == null || !mesgs.Any())
return;
await e.Channel.DeleteMessages(msgs).ConfigureAwait(false);
await e.Channel.DeleteMessages(mesgs as Message[] ?? mesgs.ToArray()).ConfigureAwait(false);
});
cgb.CreateCommand(Prefix + "die")
.Description("Shuts the bot down and notifies users about the restart. **Bot Owner Only!**")
.Description($"Shuts the bot down and notifies users about the restart. **Bot Owner Only!** | `{Prefix}die`")
.AddCheck(SimpleCheckers.OwnerOnly())
.Do(async e =>
{
@ -807,7 +807,7 @@ namespace NadekoBot.Modules.Administration
});
cgb.CreateCommand(Prefix + "unstuck")
.Description("Clears the message queue. **Bot Owner Only!**")
.Description($"Clears the message queue. **Bot Owner Only!** | `{Prefix}unstuck`")
.AddCheck(SimpleCheckers.OwnerOnly())
.Do(e =>
{
@ -815,7 +815,7 @@ namespace NadekoBot.Modules.Administration
});
cgb.CreateCommand(Prefix + "donators")
.Description("List of lovely people who donated to keep this project alive.")
.Description($"List of lovely people who donated to keep this project alive. | `{Prefix}donators`")
.Do(async e =>
{
await Task.Run(async () =>
@ -829,7 +829,7 @@ namespace NadekoBot.Modules.Administration
});
cgb.CreateCommand(Prefix + "donadd")
.Description($"Add a donator to the database. | `.donadd Donate Amount`")
.Description($"Add a donator to the database. **Kwoth Only** | `{Prefix}donadd Donate Amount`")
.Parameter("donator")
.Parameter("amount")
.AddCheck(SimpleCheckers.OwnerOnly())
@ -842,7 +842,7 @@ namespace NadekoBot.Modules.Administration
if (donator == null) return;
try
{
DbHandler.Instance.InsertData(new Donator
DbHandler.Instance.Connection.Insert(new Donator
{
Amount = amount,
UserName = donator.Name,

View File

@ -34,7 +34,7 @@ namespace NadekoBot.Modules.Administration.Commands
{
cgb.CreateCommand(Module.Prefix + "autoassignrole")
.Alias(Module.Prefix + "aar")
.Description($"Automaticaly assigns a specified role to every user who joins the server. Type `.aar` to disable, `.aar Role Name` to enable")
.Description($"Automaticaly assigns a specified role to every user who joins the server. **Needs Manage Roles Permissions.** |`{Prefix}aar` to disable, `{Prefix}aar Role Name` to enable")
.Parameter("role", ParameterType.Unparsed)
.AddCheck(new SimpleCheckers.ManageRoles())
.Do(async e =>

View File

@ -64,8 +64,8 @@ namespace NadekoBot.Modules.Administration.Commands
internal override void Init(CommandGroupBuilder cgb)
{
cgb.CreateCommand(Module.Prefix + "scsc")
.Description("Starts an instance of cross server channel. You will get a token as a DM" +
"that other people will use to tune in to the same instance")
.Description("Starts an instance of cross server channel. You will get a token as a DM " +
$"that other people will use to tune in to the same instance. **Bot Owner Only.** | `{Prefix}scsc`")
.AddCheck(SimpleCheckers.OwnerOnly())
.Do(async e =>
{
@ -79,7 +79,7 @@ namespace NadekoBot.Modules.Administration.Commands
});
cgb.CreateCommand(Module.Prefix + "jcsc")
.Description("Joins current channel to an instance of cross server channel using the token.")
.Description($"Joins current channel to an instance of cross server channel using the token. **Needs Manage Server Permissions.**| `{Prefix}jcsc`")
.Parameter("token")
.AddCheck(SimpleCheckers.ManageServer())
.Do(async e =>
@ -95,7 +95,7 @@ namespace NadekoBot.Modules.Administration.Commands
});
cgb.CreateCommand(Module.Prefix + "lcsc")
.Description("Leaves Cross server channel instance from this channel")
.Description($"Leaves Cross server channel instance from this channel. **Needs Manage Server Permissions.**| `{Prefix}lcsc`")
.AddCheck(SimpleCheckers.ManageServer())
.Do(async e =>
{

View File

@ -23,7 +23,7 @@ namespace NadekoBot.Modules.Administration.Commands
cgb.CreateCommand(Prefix + "addcustreact")
.Alias(Prefix + "acr")
.Description($"Add a custom reaction. Guide here: <https://github.com/Kwoth/NadekoBot/wiki/Custom-Reactions> **Bot Owner Only!** | {Prefix}acr \"hello\" I love saying hello to %user%")
.Description($"Add a custom reaction. Guide here: <https://github.com/Kwoth/NadekoBot/wiki/Custom-Reactions> **Bot Owner Only!** | `{Prefix}acr \"hello\" I love saying hello to %user%`")
.AddCheck(SimpleCheckers.OwnerOnly())
.Parameter("name", ParameterType.Required)
.Parameter("message", ParameterType.Unparsed)
@ -47,7 +47,7 @@ namespace NadekoBot.Modules.Administration.Commands
cgb.CreateCommand(Prefix + "listcustreact")
.Alias(Prefix + "lcr")
.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")
.Description($"Lists custom reactions (paginated with 30 commands per page). Use 'all' instead of page number to get all custom reactions DM-ed to you. |`{Prefix}lcr 1`")
.Parameter("num", ParameterType.Required)
.Do(async e =>
{
@ -80,7 +80,7 @@ namespace NadekoBot.Modules.Administration.Commands
cgb.CreateCommand(Prefix + "showcustreact")
.Alias(Prefix + "scr")
.Description($"Shows all possible responses from a single custom reaction. |{Prefix}scr %mention% bb")
.Description($"Shows all possible responses from a single custom reaction. |`{Prefix}scr %mention% bb`")
.Parameter("name", ParameterType.Unparsed)
.Do(async e =>
{
@ -106,7 +106,7 @@ namespace NadekoBot.Modules.Administration.Commands
cgb.CreateCommand(Prefix + "editcustreact")
.Alias(Prefix + "ecr")
.Description("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`")
.Description($"Edits a custom reaction, arguments are custom reactions name, index to change, and a (multiword) message **Bot Owner Only** | `{Prefix}ecr \"%mention% disguise\" 2 Test 123`")
.Parameter("name", ParameterType.Required)
.Parameter("index", ParameterType.Required)
.Parameter("message", ParameterType.Unparsed)
@ -146,7 +146,7 @@ namespace NadekoBot.Modules.Administration.Commands
cgb.CreateCommand(Prefix + "delcustreact")
.Alias(Prefix + "dcr")
.Description("Deletes a custom reaction with given name (and index)")
.Description($"Deletes a custom reaction with given name (and index). **Bot Owner Only.**| `{Prefix}dcr index`")
.Parameter("name", ParameterType.Required)
.Parameter("index", ParameterType.Optional)
.AddCheck(SimpleCheckers.OwnerOnly())

View File

@ -14,26 +14,26 @@ namespace NadekoBot.Modules.Administration.Commands
{
cgb.CreateCommand(Module.Prefix + "listincidents")
.Alias(Prefix + "lin")
.Description("List all UNREAD incidents and flags them as read.")
.Description($"List all UNREAD incidents and flags them as read. **Needs Manage Server Permissions.**| `{Prefix}lin`")
.AddCheck(SimpleCheckers.ManageServer())
.Do(async e =>
{
var sid = (long)e.Server.Id;
var incs = DbHandler.Instance.FindAll<Incident>(i => i.ServerId == sid && i.Read == false);
DbHandler.Instance.UpdateAll<Incident>(incs.Select(i => { i.Read = true; return i; }));
DbHandler.Instance.Connection.UpdateAll(incs.Select(i => { i.Read = true; return i; }));
await e.User.SendMessage(string.Join("\n----------------------", incs.Select(i => i.Text)));
});
cgb.CreateCommand(Module.Prefix + "listallincidents")
.Alias(Prefix + "lain")
.Description("Sends you a file containing all incidents and flags them as read.")
.Description($"Sends you a file containing all incidents and flags them as read. **Needs Manage Server Permissions.**| `{Prefix}lain`")
.AddCheck(SimpleCheckers.ManageServer())
.Do(async e =>
{
var sid = (long)e.Server.Id;
var incs = DbHandler.Instance.FindAll<Incident>(i => i.ServerId == sid);
DbHandler.Instance.UpdateAll<Incident>(incs.Select(i => { i.Read = true; return i; }));
DbHandler.Instance.Connection.UpdateAll(incs.Select(i => { i.Read = true; return i; }));
var data = string.Join("\n----------------------\n", incs.Select(i => i.Text));
MemoryStream ms = new MemoryStream();
var sw = new StreamWriter(ms);

View File

@ -4,7 +4,10 @@ using NadekoBot.Classes;
using NadekoBot.Extensions;
using NadekoBot.Modules.Permissions.Classes;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace NadekoBot.Modules.Administration.Commands
{
@ -12,6 +15,8 @@ namespace NadekoBot.Modules.Administration.Commands
{
private string prettyCurrentTime => $"【{DateTime.Now:HH:mm:ss}】";
private ConcurrentBag<KeyValuePair<Channel, string>> voicePresenceUpdates = new ConcurrentBag<KeyValuePair<Channel, string>>();
public LogCommand(DiscordModule module) : base(module)
{
NadekoBot.Client.MessageReceived += MsgRecivd;
@ -45,6 +50,36 @@ namespace NadekoBot.Modules.Administration.Commands
}
catch { }
};
// start the userpresence queue
NadekoBot.OnReady += () => Task.Run(async () =>
{
while (true)
{
var toSend = new Dictionary<Channel, string>();
//take everything from the queue and merge the messages which are going to the same channel
KeyValuePair<Channel, string> item;
while (voicePresenceUpdates.TryTake(out item))
{
if (toSend.ContainsKey(item.Key))
{
toSend[item.Key] = toSend[item.Key] + Environment.NewLine + item.Value;
}
else
{
toSend.Add(item.Key, item.Value);
}
}
//send merged messages to each channel
foreach (var k in toSend)
{
try { await k.Key.SendMessage(Environment.NewLine + k.Value).ConfigureAwait(false); } catch { }
}
await Task.Delay(5000);
}
});
}
private async void ChannelUpdated(object sender, ChannelUpdatedEventArgs e)
@ -177,13 +212,13 @@ namespace NadekoBot.Modules.Administration.Commands
if (!string.IsNullOrWhiteSpace(e.Message.Text))
{
await ch.SendMessage(
$@"🕔`{prettyCurrentTime}` **New Message** `#{e.Channel.Name}`
$@"🕔`{prettyCurrentTime}` **New Message** `#{e.Channel.Name}`
👤`{e.User?.ToString() ?? ("NULL")}` {e.Message.Text.Unmention()}").ConfigureAwait(false);
}
else
{
await ch.SendMessage(
$@"🕔`{prettyCurrentTime}` **File Uploaded** `#{e.Channel.Name}`
$@"🕔`{prettyCurrentTime}` **File Uploaded** `#{e.Channel.Name}`
👤`{e.User?.ToString() ?? ("NULL")}` {e.Message.Attachments.FirstOrDefault()?.ProxyUrl}").ConfigureAwait(false);
}
@ -206,13 +241,13 @@ namespace NadekoBot.Modules.Administration.Commands
if (!string.IsNullOrWhiteSpace(e.Message.Text))
{
await ch.SendMessage(
$@"🕔`{prettyCurrentTime}` **Message** 🚮 `#{e.Channel.Name}`
$@"🕔`{prettyCurrentTime}` **Message** 🚮 `#{e.Channel.Name}`
👤`{e.User?.ToString() ?? ("NULL")}` {e.Message.Text.Unmention()}").ConfigureAwait(false);
}
else
{
await ch.SendMessage(
$@"🕔`{prettyCurrentTime}` **File Deleted** `#{e.Channel.Name}`
$@"🕔`{prettyCurrentTime}` **File Deleted** `#{e.Channel.Name}`
👤`{e.User?.ToString() ?? ("NULL")}` {e.Message.Attachments.FirstOrDefault()?.ProxyUrl}").ConfigureAwait(false);
}
}
@ -232,7 +267,7 @@ namespace NadekoBot.Modules.Administration.Commands
if ((ch = e.Server.TextChannels.Where(tc => tc.Id == chId).FirstOrDefault()) == null)
return;
await ch.SendMessage(
$@"🕔`{prettyCurrentTime}` **Message** 📝 `#{e.Channel.Name}`
$@"🕔`{prettyCurrentTime}` **Message** 📝 `#{e.Channel.Name}`
👤`{e.User?.ToString() ?? ("NULL")}`
`Old:` {e.Before.Text.Unmention()}
`New:` {e.After.Text.Unmention()}").ConfigureAwait(false);
@ -252,7 +287,7 @@ $@"🕔`{prettyCurrentTime}` **Message** 📝 `#{e.Channel.Name}`
{
if (e.Before.Status != e.After.Status)
{
await ch.SendMessage($"`{prettyCurrentTime}`**{e.Before.Name}** is now **{e.After.Status}**.").ConfigureAwait(false);
voicePresenceUpdates.Add(new KeyValuePair<Channel, string>(ch, $"`{prettyCurrentTime}`**{e.Before.Name}** is now **{e.After.Status}**."));
}
}
}
@ -340,7 +375,7 @@ $@"🕔`{prettyCurrentTime}` **Message** 📝 `#{e.Channel.Name}`
{
cgb.CreateCommand(Module.Prefix + "spmom")
.Description("Toggles whether mentions of other offline users on your server will send a pm to them.")
.Description($"Toggles whether mentions of other offline users on your server will send a pm to them. **Needs Manage Server Permissions.**| `{Prefix}spmom`")
.AddCheck(SimpleCheckers.ManageServer())
.Do(async e =>
{
@ -356,7 +391,7 @@ $@"🕔`{prettyCurrentTime}` **Message** 📝 `#{e.Channel.Name}`
});
cgb.CreateCommand(Module.Prefix + "logserver")
.Description("Toggles logging in this channel. Logs every message sent/deleted/edited on the server. **Bot Owner Only!**")
.Description($"Toggles logging in this channel. Logs every message sent/deleted/edited on the server. **Bot Owner Only!** | `{Prefix}logserver`")
.AddCheck(SimpleCheckers.OwnerOnly())
.AddCheck(SimpleCheckers.ManageServer())
.Do(async e =>
@ -371,14 +406,14 @@ $@"🕔`{prettyCurrentTime}` **Message** 📝 `#{e.Channel.Name}`
Channel ch;
if ((ch = e.Server.TextChannels.Where(tc => tc.Id == chId).FirstOrDefault()) == null)
return;
SpecificConfigurations.Default.Of (e.Server.Id).LogServerChannel = null;
SpecificConfigurations.Default.Of(e.Server.Id).LogServerChannel = null;
await e.Channel.SendMessage($"❗**NO LONGER LOGGING IN {ch.Mention} CHANNEL**❗").ConfigureAwait(false);
});
cgb.CreateCommand(Prefix + "logignore")
.Description($"Toggles whether the {Prefix}logserver command ignores this channel. Useful if you have hidden admin channel and public log channel.")
.Description($"Toggles whether the {Prefix}logserver command ignores this channel. Useful if you have hidden admin channel and public log channel. **Bot Owner Only!**| `{Prefix}logignore`")
.AddCheck(SimpleCheckers.OwnerOnly())
.AddCheck(SimpleCheckers.ManageServer())
.Do(async e =>
@ -396,7 +431,7 @@ $@"🕔`{prettyCurrentTime}` **Message** 📝 `#{e.Channel.Name}`
});
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. **Needs Manage Server Permissions.**| `{Prefix}userpresence`")
.AddCheck(SimpleCheckers.ManageServer())
.Do(async e =>
{
@ -412,7 +447,7 @@ $@"🕔`{prettyCurrentTime}` **Message** 📝 `#{e.Channel.Name}`
});
cgb.CreateCommand(Module.Prefix + "voicepresence")
.Description("Toggles logging to this channel whenever someone joins or leaves a voice channel you are in right now.")
.Description($"Toggles logging to this channel whenever someone joins or leaves a voice channel you are in right now. **Needs Manage Server Permissions.**| `{Prefix}voicerpresence`")
.Parameter("all", ParameterType.Optional)
.AddCheck(SimpleCheckers.ManageServer())
.Do(async e =>

View File

@ -57,7 +57,7 @@ namespace NadekoBot.Modules.Administration.Commands
cgb.CreateCommand(Module.Prefix + "repeatinvoke")
.Alias(Module.Prefix + "repinv")
.Description("Immediately shows the repeat message and restarts the timer.")
.Description($"Immediately shows the repeat message and restarts the timer. **Needs Manage Messages Permissions.**| `{Prefix}repinv`")
.AddCheck(SimpleCheckers.ManageMessages())
.Do(async e =>
{
@ -73,7 +73,7 @@ namespace NadekoBot.Modules.Administration.Commands
cgb.CreateCommand(Module.Prefix + "repeat")
.Description("Repeat a message every X minutes. If no parameters are specified, " +
"repeat is disabled. Requires manage messages. |`.repeat 5 Hello there`")
$"repeat is disabled. **Needs Manage Messages Permissions.** |`{Prefix}repeat 5 Hello there`")
.Parameter("minutes", ParameterType.Optional)
.Parameter("msg", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.ManageMessages())

View File

@ -96,14 +96,14 @@ namespace NadekoBot.Modules.Administration.Commands
{
cgb.CreateCommand(Module.Prefix + "rotateplaying")
.Alias(Module.Prefix + "ropl")
.Description("Toggles rotation of playing status of the dynamic strings you specified earlier.")
.Description($"Toggles rotation of playing status of the dynamic strings you specified earlier. **Bot Owner Only!** | `{Prefix}ropl`")
.AddCheck(SimpleCheckers.OwnerOnly())
.Do(DoFunc());
cgb.CreateCommand(Module.Prefix + "addplaying")
.Alias(Module.Prefix + "adpl")
.Description("Adds a specified string to the list of playing strings to rotate. " +
"Supported placeholders: " + string.Join(", ", PlayingPlaceholders.Keys))
"Supported placeholders: " + string.Join(", ", PlayingPlaceholders.Keys)+ $" **Bot Owner Only!**| `{Prefix}adpl`")
.Parameter("text", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.OwnerOnly())
.Do(async e =>
@ -126,7 +126,7 @@ namespace NadekoBot.Modules.Administration.Commands
cgb.CreateCommand(Module.Prefix + "listplaying")
.Alias(Module.Prefix + "lipl")
.Description("Lists all playing statuses with their corresponding number.")
.Description($"Lists all playing statuses with their corresponding number. **Bot Owner Only!**| `{Prefix}lipl`")
.AddCheck(SimpleCheckers.OwnerOnly())
.Do(async e =>
{
@ -143,7 +143,7 @@ namespace NadekoBot.Modules.Administration.Commands
cgb.CreateCommand(Module.Prefix + "removeplaying")
.Alias(Module.Prefix + "repl", Module.Prefix + "rmpl")
.Description("Removes a playing string on a given number.")
.Description($"Removes a playing string on a given number. **Bot Owner Only!**| `{Prefix}rmpl`")
.Parameter("number", ParameterType.Required)
.AddCheck(SimpleCheckers.OwnerOnly())
.Do(async e =>

View File

@ -41,7 +41,7 @@ namespace NadekoBot.Modules.Administration.Commands
internal override void Init(CommandGroupBuilder cgb)
{
cgb.CreateCommand(Module.Prefix + "slowmode")
.Description("Toggles slow mode. When ON, users will be able to send only 1 message every 5 seconds.")
.Description($"Toggles slow mode. When ON, users will be able to send only 1 message every 5 seconds. **Needs Manage Messages Permissions.**| `{Prefix}slowmode`")
.AddCheck(SimpleCheckers.ManageMessages())
.Do(async e =>
{

View File

@ -17,7 +17,7 @@ namespace NadekoBot.Modules.Administration.Commands
{
cgb.CreateCommand(Module.Prefix + "asar")
.Description("Adds a role, or list of roles separated by whitespace" +
"(use quotations for multiword roles) to the list of self-assignable roles. | .asar Gamer")
$"(use quotations for multiword roles) to the list of self-assignable roles. **Needs Manage Roles Permissions.**| `{Prefix}asar Gamer`")
.Parameter("roles", ParameterType.Multiple)
.AddCheck(SimpleCheckers.CanManageRoles)
.Do(async e =>
@ -44,7 +44,7 @@ namespace NadekoBot.Modules.Administration.Commands
});
cgb.CreateCommand(Module.Prefix + "rsar")
.Description("Removes a specified role from the list of self-assignable roles.")
.Description($"Removes a specified role from the list of self-assignable roles. | `{Prefix}rsar`")
.Parameter("role", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.CanManageRoles)
.Do(async e =>
@ -69,14 +69,14 @@ namespace NadekoBot.Modules.Administration.Commands
});
cgb.CreateCommand(Module.Prefix + "lsar")
.Description("Lists all self-assignable roles.")
.Description($"Lists all self-assignable roles. | `{Prefix}lsar`")
.Parameter("roles", ParameterType.Multiple)
.Do(async e =>
{
var config = SpecificConfigurations.Default.Of(e.Server.Id);
var msg = new StringBuilder($"There are `{config.ListOfSelfAssignableRoles.Count}` self assignable roles:\n");
var toRemove = new HashSet<ulong>();
foreach (var roleId in config.ListOfSelfAssignableRoles.OrderBy(r=>r.ToString()))
foreach (var roleId in config.ListOfSelfAssignableRoles.OrderBy(r => r.ToString()))
{
var role = e.Server.GetRole(roleId);
if (role == null)
@ -98,8 +98,8 @@ namespace NadekoBot.Modules.Administration.Commands
cgb.CreateCommand(Module.Prefix + "togglexclsar").Alias(Module.Prefix +"tesar")
.Description("toggle whether the self-assigned roles should be exclusive")
cgb.CreateCommand(Module.Prefix + "togglexclsar").Alias(Module.Prefix + "tesar")
.Description($"toggle whether the self-assigned roles should be exclusive | `{Prefix}tesar`")
.AddCheck(SimpleCheckers.CanManageRoles)
.Do(async e =>
{
@ -112,7 +112,7 @@ namespace NadekoBot.Modules.Administration.Commands
cgb.CreateCommand(Module.Prefix + "iam")
.Description("Adds a role to you that you choose. " +
"Role must be on a list of self-assignable roles." +
" | .iam Gamer")
$" | `{Prefix}iam Gamer`")
.Parameter("role", ParameterType.Unparsed)
.Do(async e =>
{
@ -146,12 +146,13 @@ namespace NadekoBot.Modules.Administration.Commands
{
await e.User.AddRoles(role).ConfigureAwait(false);
}
catch(HttpException ex) when (ex.StatusCode == System.Net.HttpStatusCode.InternalServerError)
catch (HttpException ex) when (ex.StatusCode == System.Net.HttpStatusCode.InternalServerError)
{
}
catch (Exception)
catch (Exception ex)
{
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);
return;
}
var msg = await e.Channel.SendMessage($":ok:You now have {role.Name} role.").ConfigureAwait(false);
await Task.Delay(3000).ConfigureAwait(false);
@ -167,7 +168,7 @@ namespace NadekoBot.Modules.Administration.Commands
.Alias(Module.Prefix + "iamn")
.Description("Removes a role to you that you choose. " +
"Role must be on a list of self-assignable roles." +
" | .iamn Gamer")
$" | `{Prefix}iamn Gamer`")
.Parameter("role", ParameterType.Unparsed)
.Do(async e =>
{

View File

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

View File

@ -219,7 +219,7 @@ namespace NadekoBot.Modules.Administration.Commands
internal override void Init(CommandGroupBuilder cgb)
{
cgb.CreateCommand(Module.Prefix + "grdel")
.Description("Toggles automatic deletion of greet and bye messages.")
.Description($"Toggles automatic deletion of greet and bye messages. **Needs Manage Server Permissions.**| `{Prefix}grdel`")
.Do(async e =>
{
if (!e.User.ServerPermissions.ManageServer) return;
@ -232,7 +232,7 @@ namespace NadekoBot.Modules.Administration.Commands
});
cgb.CreateCommand(Module.Prefix + "greet")
.Description("Toggles anouncements on the current channel when someone joins the server.")
.Description($"Toggles anouncements on the current channel when someone joins the server. **Needs Manage Server Permissions.**| `{Prefix}greet`")
.Do(async e =>
{
if (!e.User.ServerPermissions.ManageServer) return;
@ -245,7 +245,7 @@ namespace NadekoBot.Modules.Administration.Commands
});
cgb.CreateCommand(Module.Prefix + "greetmsg")
.Description("Sets a new join announcement message. Type %user% if you want to mention the new member. Using it with no message will show the current greet message. | .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. **Needs Manage Server Permissions.**| `{Prefix}greetmsg Welcome to the server, %user%.`")
.Parameter("msg", ParameterType.Unparsed)
.Do(async e =>
{
@ -265,7 +265,7 @@ namespace NadekoBot.Modules.Administration.Commands
});
cgb.CreateCommand(Module.Prefix + "bye")
.Description("Toggles anouncements on the current channel when someone leaves the server.")
.Description($"Toggles anouncements on the current channel when someone leaves the server. | `{Prefix}bye`")
.Do(async e =>
{
if (!e.User.ServerPermissions.ManageServer) return;
@ -278,7 +278,7 @@ namespace NadekoBot.Modules.Administration.Commands
});
cgb.CreateCommand(Module.Prefix + "byemsg")
.Description("Sets a new leave announcement message. Type %user% if you want to mention the new member. Using it with no message will show the current bye message. | .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. **Needs Manage Server Permissions.**| `{Prefix}byemsg %user% has left the server.`")
.Parameter("msg", ParameterType.Unparsed)
.Do(async e =>
{
@ -297,7 +297,7 @@ namespace NadekoBot.Modules.Administration.Commands
});
cgb.CreateCommand(Module.Prefix + "byepm")
.Description("Toggles whether the good bye messages will be sent in a PM or in the text channel.")
.Description($"Toggles whether the good bye messages will be sent in a PM or in the text channel. **Needs Manage Server Permissions.**| `{Prefix}byepm`")
.Do(async e =>
{
if (!e.User.ServerPermissions.ManageServer) return;
@ -313,7 +313,7 @@ namespace NadekoBot.Modules.Administration.Commands
});
cgb.CreateCommand(Module.Prefix + "greetpm")
.Description("Toggles whether the greet messages will be sent in a PM or in the text channel.")
.Description($"Toggles whether the greet messages will be sent in a PM or in the text channel. **Needs Manage Server Permissions.**| `{Prefix}greetpm`")
.Do(async e =>
{
if (!e.User.ServerPermissions.ManageServer) return;

View File

@ -1,46 +0,0 @@
using Discord;
using Discord.Commands;
using NadekoBot.Classes;
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Threading.Tasks;
namespace NadekoBot.Modules.Administration.Commands
{
internal class VoiceNotificationCommand : DiscordCommand
{
//voicechannel/text channel
private readonly ConcurrentDictionary<Channel, Channel> subscribers = new ConcurrentDictionary<Channel, Channel>();
public Func<CommandEventArgs, Task> DoFunc() => async e =>
{
var arg = e.GetArg("voice_name");
if (string.IsNullOrWhiteSpace("voice_name"))
return;
var voiceChannel = e.Server.FindChannels(arg, ChannelType.Voice).FirstOrDefault();
if (voiceChannel == null)
return;
if (subscribers.ContainsKey(voiceChannel))
{
await e.Channel.SendMessage("`Voice channel notifications disabled.`").ConfigureAwait(false);
return;
}
if (subscribers.TryAdd(voiceChannel, e.Channel))
{
await e.Channel.SendMessage("`Voice channel notifications enabled.`").ConfigureAwait(false);
}
};
internal override void Init(CommandGroupBuilder cgb)
{
cgb.CreateCommand(Module.Prefix + "voicenotif")
.Description("Enables notifications on who joined/left the voice channel. |.voicenotif Karaoke club")
.Parameter("voice_name", ParameterType.Unparsed)
.Do(DoFunc());
}
public VoiceNotificationCommand(DiscordModule module) : base(module) { }
}
}

View File

@ -88,7 +88,7 @@ namespace NadekoBot.Modules.Administration.Commands
{
cgb.CreateCommand(Module.Prefix + "cleanv+t")
.Alias(Module.Prefix + "cv+t")
.Description("Deletes all text channels ending in `-voice` for which voicechannels are not found. **Use at your own risk.**")
.Description($"Deletes all text channels ending in `-voice` for which voicechannels are not found. **Use at your own risk.\nNeeds Manage Roles and Manage Channels Permissions.** | `{Prefix}cleanv+t`")
.AddCheck(SimpleCheckers.CanManageRoles)
.AddCheck(SimpleCheckers.ManageChannels())
.Do(async e =>
@ -120,7 +120,7 @@ namespace NadekoBot.Modules.Administration.Commands
cgb.CreateCommand(Module.Prefix + "voice+text")
.Alias(Module.Prefix + "v+t")
.Description("Creates a text channel for each voice channel only users in that voice channel can see." +
"If you are server owner, keep in mind you will see them all the time regardless.")
$"If you are server owner, keep in mind you will see them all the time regardless. **Needs Manage Roles and Manage Channels Permissions.**| `{Prefix}voice+text`")
.AddCheck(SimpleCheckers.ManageChannels())
.AddCheck(SimpleCheckers.CanManageRoles)
.Do(async e =>

View File

@ -148,7 +148,7 @@ namespace NadekoBot.Modules.ClashOfClans
cgb.CreateCommand(Prefix + "createwar")
.Alias(Prefix + "cw")
.Description($"Creates a new war by specifying a size (>10 and multiple of 5) and enemy clan name. |{Prefix}cw 15 The Enemy Clan")
.Description($"Creates a new war by specifying a size (>10 and multiple of 5) and enemy clan name. | `{Prefix}cw 15 The Enemy Clan`")
.Parameter("size")
.Parameter("enemy_clan", ParameterType.Unparsed)
.Do(async e =>
@ -186,7 +186,7 @@ namespace NadekoBot.Modules.ClashOfClans
cgb.CreateCommand(Prefix + "startwar")
.Alias(Prefix + "sw")
.Description("Starts a war with a given number.")
.Description("Starts a war with a given number. | `{Prefix}sw 15`")
.Parameter("number", ParameterType.Required)
.Do(async e =>
{
@ -211,7 +211,7 @@ namespace NadekoBot.Modules.ClashOfClans
cgb.CreateCommand(Prefix + "listwar")
.Alias(Prefix + "lw")
.Description($"Shows the active war claims by a number. Shows all wars in a short way if no number is specified. | {Prefix}lw [war_number] or {Prefix}lw")
.Description($"Shows the active war claims by a number. Shows all wars in a short way if no number is specified. | `{Prefix}lw [war_number] or {Prefix}lw`")
.Parameter("number", ParameterType.Optional)
.Do(async e =>
{
@ -253,7 +253,7 @@ namespace NadekoBot.Modules.ClashOfClans
cgb.CreateCommand(Prefix + "claim")
.Alias(Prefix + "call")
.Alias(Prefix + "c")
.Description($"Claims a certain base from a certain war. You can supply a name in the third optional argument to claim in someone else's place. | {Prefix}call [war_number] [base_number] [optional_other_name]")
.Description($"Claims a certain base from a certain war. You can supply a name in the third optional argument to claim in someone else's place. | `{Prefix}call [war_number] [base_number] [optional_other_name]`")
.Parameter("number")
.Parameter("baseNumber")
.Parameter("other_name", ParameterType.Unparsed)
@ -292,21 +292,21 @@ namespace NadekoBot.Modules.ClashOfClans
.Alias(Prefix + "cf")
.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]")
.Description($"Finish your claim with 3 stars if you destroyed a base. Optional second argument finishes for someone else. | `{Prefix}cf [war_number] [optional_other_name]`")
.Parameter("number", ParameterType.Required)
.Parameter("other_name", ParameterType.Unparsed)
.Do(e => FinishClaim(e));
cgb.CreateCommand(Prefix + "claimfinish2")
.Alias(Prefix + "cf2")
.Description($"Finish your claim with 2 stars if you destroyed a base. Optional second argument finishes for someone else. | {Prefix}cf [war_number] [optional_other_name]")
.Description($"Finish your claim with 2 stars if you destroyed a base. Optional second argument finishes for someone else. | `{Prefix}cf [war_number] [optional_other_name]`")
.Parameter("number", ParameterType.Required)
.Parameter("other_name", ParameterType.Unparsed)
.Do(e => FinishClaim(e, 2));
cgb.CreateCommand(Prefix + "claimfinish1")
.Alias(Prefix + "cf1")
.Description($"Finish your claim with 1 stars if you destroyed a base. Optional second argument finishes for someone else. | {Prefix}cf [war_number] [optional_other_name]")
.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));
@ -314,7 +314,7 @@ namespace NadekoBot.Modules.ClashOfClans
cgb.CreateCommand(Prefix + "unclaim")
.Alias(Prefix + "uncall")
.Alias(Prefix + "uc")
.Description($"Removes your claim from a certain war. Optional second argument denotes a person in whose place to unclaim | {Prefix}uc [war_number] [optional_other_name]")
.Description($"Removes your claim from a certain war. Optional second argument denotes a person in whose place to unclaim | `{Prefix}uc [war_number] [optional_other_name]`")
.Parameter("number", ParameterType.Required)
.Parameter("other_name", ParameterType.Unparsed)
.Do(async e =>
@ -344,7 +344,7 @@ namespace NadekoBot.Modules.ClashOfClans
cgb.CreateCommand(Prefix + "endwar")
.Alias(Prefix + "ew")
.Description($"Ends the war with a given index. |{Prefix}ew [war_number]")
.Description($"Ends the war with a given index. | `{Prefix}ew [war_number]`")
.Parameter("number")
.Do(async e =>
{

View File

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

View File

@ -8,7 +8,6 @@ using NadekoBot.Modules.Permissions.Classes;
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
@ -42,7 +41,7 @@ namespace NadekoBot.Modules.Conversations
if (string.IsNullOrWhiteSpace(text))
return;
await Task.Run(() =>
Classes.DbHandler.Instance.InsertData(new DataModels.UserQuote()
Classes.DbHandler.Instance.Connection.Insert(new DataModels.UserQuote()
{
DateAdded = DateTime.Now,
Keyword = e.GetArg("keyword").ToLowerInvariant(),
@ -102,7 +101,7 @@ namespace NadekoBot.Modules.Conversations
commands.ForEach(cmd => cmd.Init(cgb));
cgb.CreateCommand("die")
.Description("Works only for the owner. Shuts the bot down.")
.Description("Works only for the owner. Shuts the bot down. | `@NadekoBot die`")
.Do(async e =>
{
if (NadekoBot.IsOwner(e.User.Id))
@ -119,7 +118,7 @@ namespace NadekoBot.Modules.Conversations
randServerSw.Start();
cgb.CreateCommand("do you love me")
.Description("Replies with positive answer only to the bot owner.")
.Description("Replies with positive answer only to the bot owner. | `@NadekoBot do you love me`")
.Do(async e =>
{
if (NadekoBot.IsOwner(e.User.Id))
@ -130,7 +129,7 @@ namespace NadekoBot.Modules.Conversations
cgb.CreateCommand("how are you")
.Alias("how are you?")
.Description("Replies positive only if bot owner is online.")
.Description("Replies positive only if bot owner is online. | `@NadekoBot how are you`")
.Do(async e =>
{
if (NadekoBot.IsOwner(e.User.Id))
@ -150,7 +149,7 @@ namespace NadekoBot.Modules.Conversations
});
cgb.CreateCommand("fire")
.Description("Shows a unicode fire message. Optional parameter [x] tells her how many times to repeat the fire. | @NadekoBot fire [x]")
.Description("Shows a unicode fire message. Optional parameter [x] tells her how many times to repeat the fire. | `@NadekoBot fire [x]`")
.Parameter("times", ParameterType.Optional)
.Do(async e =>
{
@ -174,7 +173,7 @@ namespace NadekoBot.Modules.Conversations
});
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.** | `@NadekoBot dump`")
.Do(async e =>
{
if (!NadekoBot.IsOwner(e.User.Id)) return;
@ -201,7 +200,7 @@ namespace NadekoBot.Modules.Conversations
});
cgb.CreateCommand("ab")
.Description("Try to get 'abalabahaha'")
.Description("Try to get 'abalabahaha'| `@NadekoBot ab`")
.Do(async e =>
{
string[] strings = { "ba", "la", "ha" };

View File

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

View File

@ -1,14 +1,13 @@
using NadekoBot.Classes;
using Discord;
using Discord.Commands;
using NadekoBot.Classes;
using NadekoBot.Extensions;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Discord.Commands;
using System.Collections.Concurrent;
using Discord;
using NadekoBot.Extensions;
using System.Threading;
using System.Threading.Tasks;
namespace NadekoBot.Modules.Gambling.Commands
{
@ -23,8 +22,9 @@ namespace NadekoBot.Modules.Gambling.Commands
internal override void Init(CommandGroupBuilder cgb)
{
cgb.CreateCommand(Prefix + "race")
.Description("Starts a new animal race.")
.Do(e => {
.Description($"Starts a new animal race. | `{Prefix}race`")
.Do(e =>
{
var ar = new AnimalRace(e.Server.Id, e.Channel);
if (ar.Fail)
{
@ -35,9 +35,10 @@ namespace NadekoBot.Modules.Gambling.Commands
cgb.CreateCommand(Prefix + "joinrace")
.Alias(Prefix + "jr")
.Description("Joins a new race. You can specify an amount of flowers for betting (optional). You will get YourBet*(participants-1) back if you win. | `$jr` or `$jr 5`")
.Description($"Joins a new race. You can specify an amount of flowers for betting (optional). You will get YourBet*(participants-1) back if you win. | `{Prefix}jr` or `{Prefix}jr 5`")
.Parameter("amount", ParameterType.Optional)
.Do(async e => {
.Do(async e =>
{
int amount;
if (!int.TryParse(e.GetArg("amount"), out amount) || amount < 0)
@ -55,11 +56,13 @@ namespace NadekoBot.Modules.Gambling.Commands
await FlowersHandler.RemoveFlowers(e.User, "BetRace", (int)amount, true).ConfigureAwait(false);
AnimalRace ar;
if (!AnimalRaces.TryGetValue(e.Server.Id, out ar)) {
if (!AnimalRaces.TryGetValue(e.Server.Id, out ar))
{
await e.Channel.SendMessage("No race exists on this server");
return;
}
await ar.JoinRace(e.User, amount);
});
}
@ -93,7 +96,7 @@ namespace NadekoBot.Modules.Gambling.Commands
{
try
{
await raceChannel.SendMessage($"🏁`Race is starting in 20 seconds or when the room is full. Type $jr to join the race.`");
await raceChannel.SendMessage($"🏁`Race is starting in 20 seconds or when the room is full. Type {NadekoBot.Config.CommandPrefixes.Gambling}jr to join the race.`");
var t = await Task.WhenAny(Task.Delay(20000, token), fullgame);
Started = true;
cancelSource.Cancel();
@ -103,7 +106,7 @@ namespace NadekoBot.Modules.Gambling.Commands
}
else if (participants.Count > 1)
{
await raceChannel.SendMessage("🏁`Game starting with " + participants.Count + " praticipants.`");
await raceChannel.SendMessage("🏁`Game starting with " + participants.Count + " participants.`");
}
else
{
@ -127,7 +130,8 @@ namespace NadekoBot.Modules.Gambling.Commands
AnimalRaces.TryRemove(serverId, out throwaway);
}
private async Task StartRace() {
private async Task StartRace()
{
var rng = new Random();
Participant winner = null;
Message msg = null;
@ -163,14 +167,14 @@ namespace NadekoBot.Modules.Gambling.Commands
|🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🔚|";
if (msg == null || messagesSinceGameStarted >= 10) // also resend the message if channel was spammed
{
if(msg != null)
if (msg != null)
try { await msg.Delete(); } catch { }
msg = await raceChannel.SendMessage(text);
messagesSinceGameStarted = 0;
}
else
await msg.Edit(text);
await Task.Delay(2500);
}
}
@ -199,10 +203,11 @@ namespace NadekoBot.Modules.Gambling.Commands
messagesSinceGameStarted++;
}
private async Task CheckForFullGameAsync(CancellationToken cancelToken) {
private async Task CheckForFullGameAsync(CancellationToken cancelToken)
{
while (animals.Count > 0)
{
await Task.Delay(100,cancelToken);
await Task.Delay(100, cancelToken);
}
}
@ -257,8 +262,8 @@ namespace NadekoBot.Modules.Gambling.Commands
public override bool Equals(object obj)
{
var p = obj as Participant;
return p == null?
false:
return p == null ?
false :
p.User == User;
}
@ -279,7 +284,8 @@ namespace NadekoBot.Modules.Gambling.Commands
{
return str + "`3rd`";
}
else {
else
{
return str + $"`{Place}th`";
}

View File

@ -21,18 +21,18 @@ namespace NadekoBot.Modules.Gambling
{
cgb.CreateCommand(Module.Prefix + "roll")
.Description("Rolls 0-100. If you supply a number [x] it rolls up to 30 normal dice." +
" If you split 2 numbers with letter d (xdy) it will roll x dice from 1 to y. | $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. | `{Prefix}roll` or `{Prefix}roll 7` or `{Prefix}roll 3d5`")
.Parameter("num", ParameterType.Optional)
.Do(RollFunc());
cgb.CreateCommand(Module.Prefix + "rolluo")
.Description("Rolls 0-100. If you supply a number [x] it rolls up to 30 normal dice (unordered)." +
" If you split 2 numbers with letter d (xdy) it will roll x dice from 1 to y. | $roll or $roll 7 or $roll 3d5")
$" If you split 2 numbers with letter d (xdy) it will roll x dice from 1 to y. | `{Prefix}roll` or `{Prefix}roll` 7 or `{Prefix}roll 3d5`")
.Parameter("num", ParameterType.Optional)
.Do(RollFunc(false));
cgb.CreateCommand(Module.Prefix + "nroll")
.Description("Rolls in a given range. | `$nroll 5` (rolls 0-5) or `$nroll 5-15`")
.Description($"Rolls in a given range. | `{Prefix}nroll 5` (rolls 0-5) or `{Prefix}nroll 5-15`")
.Parameter("range", ParameterType.Required)
.Do(NRollFunc());
}

View File

@ -17,13 +17,13 @@ namespace NadekoBot.Modules.Gambling
internal override void Init(CommandGroupBuilder cgb)
{
cgb.CreateCommand(Module.Prefix + "draw")
.Description("Draws a card from the deck.If you supply number [x], she draws up to 5 cards from the deck. | $draw [x]")
.Description($"Draws a card from the deck.If you supply number [x], she draws up to 5 cards from the deck. | `{Prefix}draw [x]`")
.Parameter("count", ParameterType.Optional)
.Do(DrawCardFunc());
cgb.CreateCommand(Module.Prefix + "shuffle")
.Alias(Module.Prefix + "sh")
.Description("Reshuffles all cards back into the deck.")
.Description($"Reshuffles all cards back into the deck.|`{Prefix}shuffle`")
.Do(ReshuffleTask());
}

View File

@ -15,7 +15,7 @@ namespace NadekoBot.Modules.Gambling
internal override void Init(CommandGroupBuilder cgb)
{
cgb.CreateCommand(Module.Prefix + "flip")
.Description("Flips coin(s) - heads or tails, and shows an image. | `$flip` or `$flip 3`")
.Description($"Flips coin(s) - heads or tails, and shows an image. | `{Prefix}flip` or `{Prefix}flip 3`")
.Parameter("count", ParameterType.Optional)
.Do(FlipCoinFunc());

View File

@ -33,7 +33,7 @@ namespace NadekoBot.Modules.Gambling
commands.ForEach(com => com.Init(cgb));
cgb.CreateCommand(Prefix + "raffle")
.Description($"Prints a name and ID of a random user from the online list from the (optional) role. | `{Prefix}raffle` or `{Prefix}raffle RoleName")
.Description($"Prints a name and ID of a random user from the online list from the (optional) role. | `{Prefix}raffle` or `{Prefix}raffle RoleName`")
.Parameter("role", ParameterType.Optional)
.Do(async e =>
{
@ -63,7 +63,7 @@ namespace NadekoBot.Modules.Gambling
});
cgb.CreateCommand(Prefix + "give")
.Description(string.Format("Give someone a certain amount of {0}s", NadekoBot.Config.CurrencyName))
.Description(string.Format("Give someone a certain amount of {0}s", NadekoBot.Config.CurrencyName)+ $"|`{Prefix}give 1 \"@SomeGuy\"`")
.Parameter("amount", ParameterType.Required)
.Parameter("receiver", ParameterType.Unparsed)
.Do(async e =>
@ -140,7 +140,7 @@ namespace NadekoBot.Modules.Gambling
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")
.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 =>
{
@ -187,6 +187,7 @@ namespace NadekoBot.Modules.Gambling
cgb.CreateCommand(Prefix + "leaderboard")
.Alias(Prefix + "lb")
.Description($"Displays bot currency leaderboard | `{Prefix}lb`")
.Do(async e =>
{
var richestTemp = DbHandler.Instance.GetTopRichest();

View File

@ -20,7 +20,7 @@ namespace NadekoBot.Modules.Games.Commands
cgb.CreateCommand(Module.Prefix + "betray")
.Description("BETRAY GAME. Betray nadeko next turn." +
"If Nadeko cooperates - you get extra points, nadeko loses a LOT." +
"If Nadeko betrays - you both lose some points.")
$"If Nadeko betrays - you both lose some points. | `{Prefix}betray`")
.Do(async e =>
{
await ReceiveAnswer(e, Answers.Betray).ConfigureAwait(false);
@ -29,7 +29,7 @@ namespace NadekoBot.Modules.Games.Commands
cgb.CreateCommand(Module.Prefix + "cooperate")
.Description("BETRAY GAME. Cooperate with nadeko next turn." +
"If Nadeko cooperates - you both get bonus points." +
"If Nadeko betrays - you lose A LOT, nadeko gets extra.")
$"If Nadeko betrays - you lose A LOT, nadeko gets extra. | `{Prefix}cooperater`")
.Do(async e =>
{

View File

@ -1,5 +1,6 @@
using Discord.Commands;
using NadekoBot.Classes;
using NadekoBot.Extensions;
using System.Text;
//taken from
@ -291,13 +292,13 @@ namespace NadekoBot.Modules.Games.Commands
}
#endregion
}
return sb.ToString(); // Return result.
return sb.ToString().TrimTo(1995); // Return result.
}
internal override void Init(CommandGroupBuilder cgb)
{
cgb.CreateCommand(Module.Prefix + "leet")
.Description($"Converts a text to leetspeak with 6 (1-6) severity levels | {Module.Prefix}leet 3 Hello")
.Description($"Converts a text to leetspeak with 6 (1-6) severity levels | `{Module.Prefix}leet 3 Hello`")
.Parameter("level", ParameterType.Required)
.Parameter("text", ParameterType.Unparsed)
.Do(async e =>

View File

@ -65,7 +65,7 @@ namespace NadekoBot.Modules.Games.Commands
internal override void Init(CommandGroupBuilder cgb)
{
cgb.CreateCommand(Module.Prefix + "pick")
.Description("Picks a flower planted in this channel.")
.Description($"Picks a flower planted in this channel. | `{Prefix}pick`")
.Do(async e =>
{
IEnumerable<Message> msgs;
@ -91,7 +91,7 @@ namespace NadekoBot.Modules.Games.Commands
});
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) | `{Prefix}plant`")
.Do(async e =>
{
await locker.WaitAsync().ConfigureAwait(false);
@ -124,7 +124,7 @@ namespace NadekoBot.Modules.Games.Commands
cgb.CreateCommand(Prefix + "gencurrency")
.Alias(Prefix + "gc")
.Description($"Toggles currency generation on this channel. Every posted message will have 2% chance to spawn a {NadekoBot.Config.CurrencyName}. Optional parameter cooldown time in minutes, 5 minutes by default. Requires Manage Messages permission. | `>gc` or `>gc 60`")
.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. | `{Prefix}gc` or `{Prefix}gc 60`")
.AddCheck(SimpleCheckers.ManageMessages())
.Parameter("cd", ParameterType.Unparsed)
.Do(async e =>

View File

@ -18,7 +18,7 @@ namespace NadekoBot.Modules.Games.Commands
internal override void Init(CommandGroupBuilder cgb)
{
cgb.CreateCommand(Module.Prefix + "poll")
.Description("Creates a poll, only person who has manage server permission can do it. | >poll Question?;Answer1;Answ 2;A_3")
.Description($"Creates a poll, only person who has manage server permission can do it. | `{Prefix}poll Question?;Answer1;Answ 2;A_3`")
.Parameter("allargs", ParameterType.Unparsed)
.Do(async e =>
{
@ -43,7 +43,7 @@ namespace NadekoBot.Modules.Games.Commands
}).ConfigureAwait(false);
});
cgb.CreateCommand(Module.Prefix + "pollend")
.Description("Stops active poll on this server and prints the results in this channel.")
.Description($"Stops active poll on this server and prints the results in this channel. | `{Prefix}pollend`")
.Do(async e =>
{
if (!e.User.ServerPermissions.ManageChannels)

View File

@ -168,21 +168,21 @@ namespace NadekoBot.Modules.Games.Commands
internal override void Init(CommandGroupBuilder cgb)
{
cgb.CreateCommand(Module.Prefix + "typestart")
.Description("Starts a typing contest.")
.Description($"Starts a typing contest. | `{Prefix}typestart`")
.Do(DoFunc());
cgb.CreateCommand(Module.Prefix + "typestop")
.Description("Stops a typing contest on the current channel.")
.Description($"Stops a typing contest on the current channel. | `{Prefix}typestop`")
.Do(QuitFunc());
cgb.CreateCommand(Module.Prefix + "typeadd")
.Description("Adds a new article to the typing contest. Owner only.")
.Description($"Adds a new article to the typing contest. Owner only. | `{Prefix}typeadd wordswords`")
.Parameter("text", ParameterType.Unparsed)
.Do(async e =>
{
if (!NadekoBot.IsOwner(e.User.Id) || string.IsNullOrWhiteSpace(e.GetArg("text"))) return;
DbHandler.Instance.InsertData(new TypingArticle
DbHandler.Instance.Connection.Insert(new TypingArticle
{
Text = e.GetArg("text"),
DateAdded = DateTime.Now

View File

@ -46,7 +46,7 @@ namespace NadekoBot.Modules.Games.Commands
});
cgb.CreateCommand(Module.Prefix + "tl")
.Description("Shows a current trivia leaderboard.")
.Description($"Shows a current trivia leaderboard. | `{Prefix}tl`")
.Do(async e =>
{
TriviaGame trivia;
@ -57,7 +57,7 @@ namespace NadekoBot.Modules.Games.Commands
});
cgb.CreateCommand(Module.Prefix + "tq")
.Description("Quits current trivia after current question.")
.Description($"Quits current trivia after current question. | `{Prefix}tq`")
.Do(async e =>
{
TriviaGame trivia;

View File

@ -60,7 +60,7 @@ namespace NadekoBot.Modules.Games
try
{
await e.Channel.SendMessage(
$":question: **Question**: `{question}` \n🎱 **8Ball Answers**: `{NadekoBot.Config._8BallResponses[rng.Next(0, NadekoBot.Config._8BallResponses.Length)]}`")
$":question: `Question` __**{question}**__ \n🎱 `8Ball Answers` __**{NadekoBot.Config._8BallResponses[rng.Next(0, NadekoBot.Config._8BallResponses.Length)]}**__")
.ConfigureAwait(false);
}
catch { }

View File

@ -31,7 +31,7 @@ namespace NadekoBot.Classes.Help.Commands
if (alias != null)
str = $" / `{ com.Aliases.FirstOrDefault()}`";
if (com != null)
await e.Channel.SendMessage($@"**__Help for:__ `{com.Text}`**" + str + $"\n**Desc:** {new Regex(@"\|").Replace(com.Description, "\n**Usage:**",1)}").ConfigureAwait(false);
await e.Channel.SendMessage($@"**__Help for:__ `{com.Text}`**" + str + $"\n**Desc:** {new Regex(@"\|").Replace(com.Description, "\n**Usage:**", 1)}").ConfigureAwait(false);
}).ConfigureAwait(false);
};
public static string HelpString {
@ -48,11 +48,11 @@ namespace NadekoBot.Classes.Help.Commands
public Action<CommandEventArgs> DoGitFunc() => e =>
{
string helpstr =
$@"######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`
$@"######For more information and how to setup your own NadekoBot, go to: <http://github.com/Kwoth/NadekoBot/wiki>
######You can donate on patreon: <https://patreon.com/nadekobot>
######or paypal: `nadekodiscordbot@gmail.com`
#NadekoBot List Of Commands
Version: `{NadekoStats.Instance.BotVersion}`";
#NadekoBot List Of Commands ";
string lastCategory = "";
@ -80,16 +80,16 @@ Version: `{NadekoStats.Instance.BotVersion}`";
{
cgb.CreateCommand(Module.Prefix + "h")
.Alias(Module.Prefix + "help", NadekoBot.BotMention + " help", NadekoBot.BotMention + " h", "~h")
.Description("Either shows a help for a single command, or PMs you help link if no arguments are specified. | '-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. | `{Prefix}h !m q` or just `{Prefix}h` ")
.Parameter("command", ParameterType.Unparsed)
.Do(HelpFunc());
cgb.CreateCommand(Module.Prefix + "hgit")
.Description("Generates the commandlist.md file. **Bot Owner Only!**")
.Description($"Generates the commandlist.md file. **Bot Owner Only!** | `{Prefix}hgit`")
.AddCheck(SimpleCheckers.OwnerOnly())
.Do(DoGitFunc());
cgb.CreateCommand(Module.Prefix + "readme")
.Alias(Module.Prefix + "guide")
.Description("Sends a readme and a guide links to the channel.")
.Description($"Sends a readme and a guide links to the channel. | `{Prefix}readme` or `{Prefix}guide`")
.Do(async e =>
await e.Channel.SendMessage(
@"**Wiki with all info**: <https://github.com/Kwoth/NadekoBot/wiki>
@ -102,16 +102,15 @@ Version: `{NadekoStats.Instance.BotVersion}`";
cgb.CreateCommand(Module.Prefix + "donate")
.Alias("~donate")
.Description("Instructions for helping the project!")
.Description($"Instructions for helping the project! | `{Prefix}donate` or `~donate`")
.Do(async e =>
{
await e.Channel.SendMessage(
$@"I've created a **paypal** email for nadeko, so if you wish to support the project, you can send your donations to `nadekodiscordbot@gmail.com`
Don't forget to leave your discord name or id in the message, so that I can reward people who help out.
You can join nadekobot server by typing {Module.Prefix}h and you will get an invite in a private message.
$@"You can support the project on patreon. <https://patreon.com/nadekobot> or
You can send donations to `nadekodiscordbot@gmail.com`
Don't forget to leave your discord name or id in the message.
*If you want to support in some other way or on a different platform, please message me*"
).ConfigureAwait(false);
**Thank you** ").ConfigureAwait(false);
});
}

View File

@ -29,7 +29,7 @@ namespace NadekoBot.Modules.Help
cgb.CreateCommand(Prefix + "modules")
.Alias(".modules")
.Description("List all bot modules.")
.Description($"List all bot modules. | `{Prefix}modules` or `.modules`")
.Do(async e =>
{
await e.Channel.SendMessage("`List of modules:` \n• " + string.Join("\n• ", NadekoBot.Client.GetService<ModuleService>().Modules.Select(m => m.Name)) + $"\n`Type \"{Prefix}commands module_name\" to get a list of commands in that module.`")
@ -38,7 +38,7 @@ namespace NadekoBot.Modules.Help
cgb.CreateCommand(Prefix + "commands")
.Alias(".commands")
.Description("List all of the bot's commands from a certain module.")
.Description($"List all of the bot's commands from a certain module. | `{Prefix}commands` or `.commands`")
.Parameter("module", ParameterType.Unparsed)
.Do(async e =>
{

View File

@ -34,7 +34,7 @@ namespace NadekoBot.Modules.Music.Classes
public IReadOnlyCollection<Song> Playlist => playlist;
public Song CurrentSong { get; private set; }
private CancellationTokenSource SongCancelSource { get; set; }
public CancellationTokenSource SongCancelSource { get; private set; }
private CancellationToken cancelToken { get; set; }
public bool Paused { get; set; }

View File

@ -32,7 +32,6 @@ namespace NadekoBot.Modules.Music.Classes
public SongInfo SongInfo { get; }
public string QueuerName { get; set; }
private bool bufferingCompleted { get; set; } = false;
public MusicPlayer MusicPlayer { get; set; }
public string PrettyCurrentTime()
@ -73,78 +72,22 @@ namespace NadekoBot.Modules.Music.Classes
return this;
}
private Task BufferSong(string filename, CancellationToken cancelToken) =>
Task.Factory.StartNew(async () =>
{
Process p = null;
try
{
p = Process.Start(new ProcessStartInfo
{
FileName = "ffmpeg",
Arguments = $"-ss {skipTo} -i {SongInfo.Uri} -f s16le -ar 48000 -ac 2 pipe:1 -loglevel quiet",
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = false,
CreateNoWindow = true,
});
var prebufferSize = 100ul.MiB();
using (var outStream = new FileStream(filename, FileMode.Append, FileAccess.Write, FileShare.Read))
{
byte[] buffer = new byte[81920];
int bytesRead;
while ((bytesRead = await p.StandardOutput.BaseStream.ReadAsync(buffer, 0, buffer.Length, cancelToken).ConfigureAwait(false)) != 0)
{
await outStream.WriteAsync(buffer, 0, bytesRead, cancelToken).ConfigureAwait(false);
while ((ulong)outStream.Length - bytesSent > prebufferSize)
await Task.Delay(100, cancelToken);
}
}
bufferingCompleted = true;
}
catch (System.ComponentModel.Win32Exception) {
var oldclr = Console.ForegroundColor;
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(@"You have not properly installed or configured FFMPEG.
Please install and configure FFMPEG to play music.
Check the guides for your platform on how to setup ffmpeg correctly:
Windows Guide: https://goo.gl/SCv72y
Linux Guide: https://goo.gl/rRhjCp");
Console.ForegroundColor = oldclr;
}
catch (Exception ex)
{
Console.WriteLine($"Buffering stopped: {ex.Message}");
}
finally
{
Console.WriteLine($"Buffering done.");
if (p != null)
{
try
{
p.Kill();
}
catch { }
p.Dispose();
}
}
}, TaskCreationOptions.LongRunning);
internal async Task Play(IAudioClient voiceClient, CancellationToken cancelToken)
{
var filename = Path.Combine(MusicModule.MusicDataPath, DateTime.Now.UnixTimestamp().ToString());
var bufferTask = BufferSong(filename, cancelToken).ConfigureAwait(false);
SongBuffer sb = new SongBuffer(filename, SongInfo, skipTo);
var bufferTask = sb.BufferSong(cancelToken).ConfigureAwait(false);
var inStream = new FileStream(filename, FileMode.OpenOrCreate, FileAccess.Read, FileShare.Write);
var inStream = new FileStream(sb.GetNextFile(), FileMode.OpenOrCreate, FileAccess.Read, FileShare.Write); ;
bytesSent = 0;
try
{
var prebufferingTask = CheckPrebufferingAsync(inStream, cancelToken);
var attempt = 0;
var prebufferingTask = CheckPrebufferingAsync(inStream, sb, cancelToken);
var sw = new Stopwatch();
sw.Start();
var t = await Task.WhenAny(prebufferingTask, Task.Delay(5000, cancelToken));
@ -162,7 +105,6 @@ Check the guides for your platform on how to setup ffmpeg correctly:
Console.WriteLine("Prebuffering successfully completed in "+ sw.Elapsed);
const int blockSize = 3840;
var attempt = 0;
byte[] buffer = new byte[blockSize];
while (!cancelToken.IsCancellationRequested)
{
@ -173,14 +115,31 @@ Check the guides for your platform on how to setup ffmpeg correctly:
{
bytesSent += (ulong)read;
}
if (read == 0)
if (attempt++ == 20)
if (read < blockSize)
{
if (sb.IsNextFileReady())
{
voiceClient.Wait();
break;
inStream.Dispose();
inStream = new FileStream(sb.GetNextFile(), FileMode.Open, FileAccess.Read, FileShare.Write);
read += inStream.Read(buffer, read, buffer.Length - read);
attempt = 0;
}
if (read == 0)
{
if (sb.BufferingCompleted)
break;
if (attempt++ == 20)
{
voiceClient.Wait();
MusicPlayer.SongCancelSource.Cancel();
break;
}
else
await Task.Delay(100, cancelToken).ConfigureAwait(false);
}
else
await Task.Delay(100, cancelToken).ConfigureAwait(false);
attempt = 0;
}
else
attempt = 0;
@ -195,14 +154,16 @@ Check the guides for your platform on how to setup ffmpeg correctly:
{
await bufferTask;
await Task.Run(() => voiceClient.Clear());
inStream.Dispose();
try { File.Delete(filename); } catch { }
if(inStream != null)
inStream.Dispose();
Console.WriteLine("l");
sb.CleanFiles();
}
}
private async Task CheckPrebufferingAsync(Stream inStream, CancellationToken cancelToken)
private async Task CheckPrebufferingAsync(Stream inStream, SongBuffer sb, CancellationToken cancelToken)
{
while (!bufferingCompleted && inStream.Length < 2.MiB())
while (!sb.BufferingCompleted && inStream.Length < 2.MiB())
{
await Task.Delay(100, cancelToken);
}

View File

@ -0,0 +1,159 @@
using NadekoBot.Extensions;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace NadekoBot.Modules.Music.Classes
{
/// <summary>
/// Create a buffer for a song file. It will create multiples files to ensure, that radio don't fill up disk space.
/// It also help for large music by deleting files that are already seen.
/// </summary>
class SongBuffer
{
public SongBuffer(string basename, SongInfo songInfo, int skipTo)
{
Basename = basename;
SongInfo = songInfo;
SkipTo = skipTo;
}
private string Basename;
private SongInfo SongInfo;
private int SkipTo;
private static int MAX_FILE_SIZE = 20.MiB();
private long FileNumber = -1;
private long NextFileToRead = 0;
public bool BufferingCompleted { get; private set;} = false;
private ulong CurrentBufferSize = 0;
public Task BufferSong(CancellationToken cancelToken) =>
Task.Factory.StartNew(async () =>
{
Process p = null;
FileStream outStream = null;
try
{
p = Process.Start(new ProcessStartInfo
{
FileName = "ffmpeg",
Arguments = $"-ss {SkipTo} -i {SongInfo.Uri} -f s16le -ar 48000 -ac 2 pipe:1 -loglevel quiet",
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = false,
CreateNoWindow = true,
});
byte[] buffer = new byte[81920];
int currentFileSize = 0;
ulong prebufferSize = 100ul.MiB();
outStream = new FileStream(Basename + "-" + ++FileNumber, FileMode.Append, FileAccess.Write, FileShare.Read);
while (!p.HasExited) //Also fix low bandwidth
{
int bytesRead = await p.StandardOutput.BaseStream.ReadAsync(buffer, 0, buffer.Length, cancelToken).ConfigureAwait(false);
if (currentFileSize >= MAX_FILE_SIZE)
{
try
{
outStream.Dispose();
}catch { }
outStream = new FileStream(Basename + "-" + ++FileNumber, FileMode.Append, FileAccess.Write, FileShare.Read);
currentFileSize = bytesRead;
}
else
{
currentFileSize += bytesRead;
}
CurrentBufferSize += Convert.ToUInt64(bytesRead);
await outStream.WriteAsync(buffer, 0, bytesRead, cancelToken).ConfigureAwait(false);
while (CurrentBufferSize > prebufferSize)
await Task.Delay(100, cancelToken);
}
BufferingCompleted = true;
}
catch (System.ComponentModel.Win32Exception)
{
var oldclr = Console.ForegroundColor;
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(@"You have not properly installed or configured FFMPEG.
Please install and configure FFMPEG to play music.
Check the guides for your platform on how to setup ffmpeg correctly:
Windows Guide: https://goo.gl/SCv72y
Linux Guide: https://goo.gl/rRhjCp");
Console.ForegroundColor = oldclr;
}
catch (Exception ex)
{
Console.WriteLine($"Buffering stopped: {ex.Message}");
}
finally
{
if(outStream != null)
outStream.Dispose();
Console.WriteLine($"Buffering done.");
if (p != null)
{
try
{
p.Kill();
}
catch { }
p.Dispose();
}
}
}, TaskCreationOptions.LongRunning);
/// <summary>
/// Return the next file to read, and delete the old one
/// </summary>
/// <returns>Name of the file to read</returns>
public string GetNextFile()
{
string filename = Basename + "-" + NextFileToRead;
if (NextFileToRead != 0)
{
try
{
CurrentBufferSize -= Convert.ToUInt64(new FileInfo(Basename + "-" + (NextFileToRead - 1)).Length);
File.Delete(Basename + "-" + (NextFileToRead - 1));
}
catch { }
}
NextFileToRead++;
return filename;
}
public bool IsNextFileReady()
{
return NextFileToRead <= FileNumber;
}
public void CleanFiles()
{
for (long i = NextFileToRead - 1 ; i <= FileNumber; i++)
{
try
{
File.Delete(Basename + "-" + i);
}
catch { }
}
}
}
}

View File

@ -614,11 +614,11 @@ namespace NadekoBot.Modules.Music
};
DbHandler.Instance.SaveAll(songInfos);
DbHandler.Instance.Save(playlist);
DbHandler.Instance.InsertMany(songInfos.Select(s => new PlaylistSongInfo
DbHandler.Instance.Connection.InsertAll(songInfos.Select(s => new PlaylistSongInfo
{
PlaylistId = playlist.Id.Value,
SongInfoId = s.Id.Value
}));
}), typeof(PlaylistSongInfo));
await e.Channel.SendMessage($"🎵 `Saved playlist as {name}-{playlist.Id}`").ConfigureAwait(false);
@ -718,7 +718,7 @@ namespace NadekoBot.Modules.Music
});
cgb.CreateCommand(Prefix + "goto")
.Description($"Goes to a specific time in seconds in a song. | {Prefix}goto 30")
.Description($"Goes to a specific time in seconds in a song. | `{Prefix}goto 30`")
.Parameter("time")
.Do(async e =>
{
@ -756,21 +756,42 @@ namespace NadekoBot.Modules.Music
cgb.CreateCommand(Prefix + "getlink")
.Alias(Prefix + "gl")
.Description("Shows a link to the currently playing song.")
.Description($"Shows a link to the song in the queue by index, or the currently playing song by default. | `{Prefix}gl`")
.Parameter("index", ParameterType.Optional)
.Do(async e =>
{
MusicPlayer musicPlayer;
if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer))
return;
var curSong = musicPlayer.CurrentSong;
if (curSong == null)
return;
await e.Channel.SendMessage($"🎶`Current song:` <{curSong.SongInfo.Query}>").ConfigureAwait(false);
int index;
string arg = e.GetArg("index")?.Trim();
if (!string.IsNullOrEmpty(arg) && int.TryParse(arg, out index))
{
var selSong = musicPlayer.Playlist.DefaultIfEmpty(null).ElementAtOrDefault(index - 1);
if (selSong == null)
{
await e.Channel.SendMessage("Could not select song, likely wrong index");
}
else
{
await e.Channel.SendMessage($"🎶`Selected song {selSong.SongInfo.Title}:` <{selSong.SongInfo.Query}>").ConfigureAwait(false);
}
}
else
{
var curSong = musicPlayer.CurrentSong;
if (curSong == null)
return;
await e.Channel.SendMessage($"🎶`Current song:` <{curSong.SongInfo.Query}>").ConfigureAwait(false);
}
});
cgb.CreateCommand(Prefix + "autoplay")
.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) | `{Prefix}ap`")
.Do(async e =>
{
@ -818,7 +839,7 @@ namespace NadekoBot.Modules.Music
lastFinishedMessage = await textCh.SendMessage($"🎵`Finished`{song.PrettyName}").ConfigureAwait(false);
if (mp.Autoplay && mp.Playlist.Count == 0 && song.SongInfo.Provider == "YouTube")
{
await QueueSong(queuer, textCh, voiceCh, await SearchHelper.GetRelatedVideoId(song.SongInfo.Query), silent, musicType).ConfigureAwait(false);
await QueueSong(queuer.Server.CurrentUser, textCh, voiceCh, (await SearchHelper.GetRelatedVideoIds(song.SongInfo.Query, 4)).ToList().Shuffle().FirstOrDefault(), silent, musicType).ConfigureAwait(false);
}
}
catch (Exception e)

View File

@ -4,6 +4,8 @@ using NadekoBot.Classes;
using NadekoBot.Modules.Permissions.Classes;
using Newtonsoft.Json.Linq;
using System;
using System.Linq;
using System.Threading.Tasks;
namespace NadekoBot.Modules.NSFW
{
@ -27,16 +29,16 @@ namespace NadekoBot.Modules.NSFW
.Do(async e =>
{
var tag = e.GetArg("tag")?.Trim() ?? "";
var gel = await SearchHelper.GetGelbooruImageLink("rating%3Aexplicit+" + tag).ConfigureAwait(false);
if (gel != null)
await e.Channel.SendMessage(":heart: Gelbooru: " + gel)
.ConfigureAwait(false);
var dan = await SearchHelper.GetDanbooruImageLink("rating%3Aexplicit+" + tag).ConfigureAwait(false);
if (dan != null)
await e.Channel.SendMessage(":heart: Danbooru: " + dan)
.ConfigureAwait(false);
if (dan == null && gel == null)
var links = await Task.WhenAll(SearchHelper.GetGelbooruImageLink("rating%3Aexplicit+" + tag), SearchHelper.GetDanbooruImageLink("rating%3Aexplicit+" + tag)).ConfigureAwait(false);
if (links.All(l => l == null))
{
await e.Channel.SendMessage("`No results.`");
return;
}
await e.Channel.SendMessage(String.Join("\n\n", links)).ConfigureAwait(false);
});
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 +) | `{Prefix}danbooru yuri+kissing`")
@ -84,14 +86,14 @@ namespace NadekoBot.Modules.NSFW
await e.Channel.SendMessage(await SearchHelper.GetE621ImageLink(tag).ConfigureAwait(false)).ConfigureAwait(false);
});
cgb.CreateCommand(Prefix + "cp")
.Description("We all know where this will lead you to.")
.Description($"We all know where this will lead you to. | `{Prefix}cp`")
.Parameter("anything", ParameterType.Unparsed)
.Do(async e =>
{
await e.Channel.SendMessage("http://i.imgur.com/MZkY1md.jpg").ConfigureAwait(false);
});
cgb.CreateCommand(Prefix + "boobs")
.Description("Real adult content.")
.Description($"Real adult content. | `{Prefix}boobs`")
.Do(async e =>
{
try
@ -106,7 +108,7 @@ namespace NadekoBot.Modules.NSFW
});
cgb.CreateCommand(Prefix + "butts")
.Alias(Prefix + "ass", Prefix + "butt")
.Description("Real adult content.")
.Description($"Real adult content. | `{Prefix}butts` or `{Prefix}ass`")
.Do(async e =>
{
try

View File

@ -49,7 +49,6 @@ namespace NadekoBot.Modules.Permissions.Classes
{
return false;
}
if (timeBlackList.Contains(user.Id))
return false;
@ -64,9 +63,9 @@ namespace NadekoBot.Modules.Permissions.Classes
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 (commandCooldowns.Keys.Contains(user.Server.Id + ":" + command.Text.ToLower()))
{
if(perms?.Verbose == true)
if (perms?.Verbose == true)
error = $"{user.Mention} You have a cooldown on that command.";
return false;
}
@ -150,7 +149,8 @@ namespace NadekoBot.Modules.Permissions.Classes
}
}
public void AddUserCooldown(ulong serverId, ulong userId, string commandName) {
public void AddUserCooldown(ulong serverId, ulong userId, string commandName)
{
commandCooldowns.TryAdd(commandName, userId);
var tosave = serverId + ":" + commandName;
Task.Run(async () =>
@ -158,7 +158,8 @@ namespace NadekoBot.Modules.Permissions.Classes
ServerPermissions perms;
PermissionsHandler.PermissionsDict.TryGetValue(serverId, out perms);
int cd;
if (!perms.CommandCooldowns.TryGetValue(commandName,out cd)) {
if (!perms.CommandCooldowns.TryGetValue(commandName, out cd))
{
return;
}
if (commandCooldowns.TryAdd(tosave, userId))

View File

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

View File

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

View File

@ -33,7 +33,7 @@ namespace NadekoBot.Modules.Permissions
cgb.CreateCommand(Prefix + "permrole")
.Alias(Prefix + "pr")
.Description("Sets a role which can change permissions. Or supply no parameters to find out the current one. Default one is 'Nadeko'.")
.Description($"Sets a role which can change permissions. Or supply no parameters to find out the current one. Default one is 'Nadeko'. | `{Prefix}pr role`")
.Parameter("role", ParameterType.Unparsed)
.Do(async e =>
{
@ -158,7 +158,7 @@ namespace NadekoBot.Modules.Permissions
cgb.CreateCommand(Prefix + "srvrperms")
.Alias(Prefix + "sp")
.Description("Shows banned permissions for this server.")
.Description($"Shows banned permissions for this server. | `{Prefix}sp`")
.Do(async e =>
{
var perms = PermissionsHandler.GetServerPermissions(e.Server);
@ -813,7 +813,7 @@ namespace NadekoBot.Modules.Permissions
cgb.CreateCommand(Prefix + "allcmdcooldowns")
.Alias(Prefix + "acmdcds")
.Description("Shows a list of all commands and their respective cooldowns.")
.Description("Shows a list of all commands and their respective cooldowns. | `{Prefix}acmdcds`")
.Do(async e =>
{
ServerPermissions perms;

View File

@ -196,7 +196,7 @@ namespace NadekoBot.Modules.Pokemon
cgb.CreateCommand(Prefix + "movelist")
.Alias(Prefix + "ml")
.Description("Lists the moves you are able to use")
.Description($"Lists the moves you are able to use | `{Prefix}ml`")
.Do(async e =>
{
var userType = GetPokeType(e.User.Id);
@ -210,7 +210,7 @@ namespace NadekoBot.Modules.Pokemon
});
cgb.CreateCommand(Prefix + "heal")
.Description($"Heals someone. Revives those who fainted. Costs a {NadekoBot.Config.CurrencyName} | {Prefix}heal @someone")
.Description($"Heals someone. Revives those who fainted. Costs a {NadekoBot.Config.CurrencyName} | `{Prefix}heal @someone`")
.Parameter("target", ParameterType.Unparsed)
.Do(async e =>
{
@ -263,7 +263,7 @@ namespace NadekoBot.Modules.Pokemon
});
cgb.CreateCommand(Prefix + "type")
.Description($"Get the poketype of the target. | {Prefix}type @someone")
.Description($"Get the poketype of the target. | `{Prefix}type @someone`")
.Parameter("target", ParameterType.Unparsed)
.Do(async e =>
{
@ -282,7 +282,7 @@ namespace NadekoBot.Modules.Pokemon
});
cgb.CreateCommand(Prefix + "settype")
.Description($"Set your poketype. Costs a {NadekoBot.Config.CurrencyName}. | {Prefix}settype fire")
.Description($"Set your poketype. Costs a {NadekoBot.Config.CurrencyName}. | `{Prefix}settype fire`")
.Parameter("targetType", ParameterType.Unparsed)
.Do(async e =>
{
@ -319,11 +319,11 @@ namespace NadekoBot.Modules.Pokemon
DbHandler.Instance.Delete<UserPokeTypes>(Dict[(long)e.User.Id]);
}
DbHandler.Instance.InsertData(new UserPokeTypes
DbHandler.Instance.Connection.Insert(new UserPokeTypes
{
UserId = (long)e.User.Id,
type = targetType.Name
});
}, typeof(UserPokeTypes));
//Now for the response

View File

@ -32,7 +32,7 @@ namespace NadekoBot.Modules.Searches.Commands
internal override void Init(CommandGroupBuilder cgb)
{
cgb.CreateCommand(Module.Prefix + "convert")
.Description("Convert quantities from>to. Like `~convert m>km 1000`")
.Description($"Convert quantities from>to. | `{Prefix}convert m>km 1000`")
.Parameter("from-to", ParameterType.Required)
.Parameter("quantity", ParameterType.Optional)
.Do(ConvertFunc());

View File

@ -17,7 +17,7 @@ namespace NadekoBot.Modules.Searches.Commands
{
cgb.CreateCommand(Module.Prefix + "calculate")
.Alias(Module.Prefix + "calc")
.Description("Evaluate a mathematical expression. | ~calc 1+1")
.Description($"Evaluate a mathematical expression. | `{Prefix}calc 1+1`")
.Parameter("expression", ParameterType.Unparsed)
.Do(EvalFunc());
}

View File

@ -72,7 +72,7 @@ namespace NadekoBot.Modules.Searches.Commands
internal override void Init(CommandGroupBuilder cgb)
{
cgb.CreateCommand(Module.Prefix + "lolchamp")
.Description("Shows League Of Legends champion statistics. If there are spaces/apostrophes or in the name - omit them. Optional second parameter is a role. |~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. |`{Prefix}lolchamp Riven` or `{Prefix}lolchamp Annie sup`")
.Parameter("champ", ParameterType.Required)
.Parameter("position", ParameterType.Unparsed)
.Do(async e =>
@ -280,7 +280,7 @@ Assists: {general["assists"]} Ban: {general["banRate"]}%
});
cgb.CreateCommand(Module.Prefix + "lolban")
.Description("Shows top 6 banned champions ordered by ban rate. Ban these champions and you will be Plat 5 in no time.")
.Description($"Shows top 6 banned champions ordered by ban rate. Ban these champions and you will be Plat 5 in no time. | `{Prefix}lolban`")
.Do(async e =>
{

View File

@ -17,7 +17,7 @@ namespace NadekoBot.Modules.Searches.Commands
internal override void Init(CommandGroupBuilder cgb)
{
cgb.CreateCommand(Prefix + "memelist")
.Description("Pulls a list of memes you can use with `~memegen` from http://memegen.link/templates/")
.Description($"Pulls a list of memes you can use with `~memegen` from http://memegen.link/templates/ | `{Prefix}memelist`")
.Do(async e =>
{
int i = 0;
@ -30,7 +30,7 @@ namespace NadekoBot.Modules.Searches.Commands
});
cgb.CreateCommand(Prefix + "memegen")
.Description("Generates a meme from memelist with top and bottom text. | `~memegen biw \"gets iced coffee\" \"in the winter\"`")
.Description($"Generates a meme from memelist with top and bottom text. | `{Prefix}memegen biw \"gets iced coffee\" \"in the winter\"`")
.Parameter("meme", ParameterType.Required)
.Parameter("toptext", ParameterType.Required)
.Parameter("bottext", ParameterType.Required)

View File

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

View File

@ -22,7 +22,7 @@ namespace NadekoBot.Modules.Searches.Commands
{
cgb.CreateCommand(Prefix + "pokemon")
.Alias(Prefix + "poke")
.Description("Searches for a pokemon.")
.Description($"Searches for a pokemon. | `{Prefix}poke Sylveon`")
.Parameter("pokemon", ParameterType.Unparsed)
.Do(async e =>
{
@ -43,7 +43,7 @@ namespace NadekoBot.Modules.Searches.Commands
cgb.CreateCommand(Prefix + "pokemonability")
.Alias(Prefix + "pokeab")
.Description("Searches for a pokemon ability.")
.Description($"Searches for a pokemon ability. | `{Prefix}pokeab \"water gun\"`")
.Parameter("abil", ParameterType.Unparsed)
.Do(async e =>
{

View File

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

View File

@ -22,7 +22,7 @@ namespace NadekoBot.Modules.Searches.Commands
{
cgb.CreateCommand(Module.Prefix + "wowjoke")
.Description("Get one of Kwoth's penultimate WoW jokes.")
.Description($"Get one of Kwoth's penultimate WoW jokes. | `{Prefix}wowjoke`")
.Do(async e =>
{
if (!jokes.Any())

View File

@ -86,7 +86,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
cgb.CreateCommand(Prefix + "ani")
.Alias(Prefix + "anime", Prefix + "aq")
.Parameter("query", ParameterType.Unparsed)
.Description("Queries anilist for an anime and shows the first result.")
.Description($"Queries anilist for an anime and shows the first result. | `{Prefix}aq aquarion evol`")
.Do(async e =>
{
if (!(await SearchHelper.ValidateQuery(e.Channel, e.GetArg("query")).ConfigureAwait(false))) return;
@ -106,7 +106,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
cgb.CreateCommand(Prefix + "imdb")
.Parameter("query", ParameterType.Unparsed)
.Description($"Queries imdb for movies or series, show first result. | `{Prefix}imdb query`")
.Description($"Queries imdb for movies or series, show first result. | `{Prefix}imdb Batman vs Superman`")
.Do(async e =>
{
if (!(await SearchHelper.ValidateQuery(e.Channel, e.GetArg("query")).ConfigureAwait(false))) return;
@ -130,7 +130,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
cgb.CreateCommand(Prefix + "mang")
.Alias(Prefix + "manga").Alias(Prefix + "mq")
.Parameter("query", ParameterType.Unparsed)
.Description($"Queries anilist for a manga and shows the first result. | `{Prefix}mq query`")
.Description($"Queries anilist for a manga and shows the first result. | `{Prefix}mq Shingeki no kyojin`")
.Do(async e =>
{
if (!(await SearchHelper.ValidateQuery(e.Channel, e.GetArg("query")).ConfigureAwait(false))) return;
@ -149,7 +149,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
cgb.CreateCommand(Prefix + "randomcat")
.Alias(Prefix + "meow")
.Description("Shows a random cat image.")
.Description($"Shows a random cat image. | `{Prefix}meow`")
.Do(async e =>
{
await e.Channel.SendMessage(JObject.Parse(
@ -159,7 +159,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
cgb.CreateCommand(Prefix + "randomdog")
.Alias(Prefix + "woof")
.Description("Shows a random dog image.")
.Description($"Shows a random dog image. | `{Prefix}woof`")
.Do(async e =>
{
await e.Channel.SendMessage("http://random.dog/" + await SearchHelper.GetResponseStringAsync("http://random.dog/woof").ConfigureAwait(false)).ConfigureAwait(false);
@ -341,7 +341,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
});
cgb.CreateCommand(Prefix + "quote")
.Description("Shows a random quote.")
.Description($"Shows a random quote. | `{Prefix}quote`")
.Do(async e =>
{
var quote = NadekoBot.Config.Quotes[rng.Next(0, NadekoBot.Config.Quotes.Count)].ToString();
@ -349,7 +349,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
});
cgb.CreateCommand(Prefix + "catfact")
.Description("Shows a random catfact from <http://catfacts-api.appspot.com/api/facts>")
.Description($"Shows a random catfact from <http://catfacts-api.appspot.com/api/facts> | `{Prefix}catfact`")
.Do(async e =>
{
var response = await SearchHelper.GetResponseStringAsync("http://catfacts-api.appspot.com/api/facts").ConfigureAwait(false);
@ -360,7 +360,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
cgb.CreateCommand(Prefix + "yomama")
.Alias(Prefix + "ym")
.Description("Shows a random joke from <http://api.yomomma.info/>")
.Description($"Shows a random joke from <http://api.yomomma.info/> | `{Prefix}ym`")
.Do(async e =>
{
var response = await SearchHelper.GetResponseStringAsync("http://api.yomomma.info/").ConfigureAwait(false);
@ -369,7 +369,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
cgb.CreateCommand(Prefix + "randjoke")
.Alias(Prefix + "rj")
.Description("Shows a random joke from <http://tambal.azurewebsites.net/joke/random>")
.Description($"Shows a random joke from <http://tambal.azurewebsites.net/joke/random> | `{Prefix}rj`")
.Do(async e =>
{
var response = await SearchHelper.GetResponseStringAsync("http://tambal.azurewebsites.net/joke/random").ConfigureAwait(false);
@ -378,7 +378,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
cgb.CreateCommand(Prefix + "chucknorris")
.Alias(Prefix + "cn")
.Description("Shows a random chucknorris joke from <http://tambal.azurewebsites.net/joke/random>")
.Description($"Shows a random chucknorris joke from <http://tambal.azurewebsites.net/joke/random> | `{Prefix}cn`")
.Do(async e =>
{
var response = await SearchHelper.GetResponseStringAsync("http://api.icndb.com/jokes/random/").ConfigureAwait(false);
@ -387,7 +387,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
cgb.CreateCommand(Prefix + "magicitem")
.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> | `{Prefix}mi`")
.Do(async e =>
{
var magicItems = JsonConvert.DeserializeObject<List<MagicItem>>(File.ReadAllText("data/magicitems.json"));
@ -397,7 +397,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
});
cgb.CreateCommand(Prefix + "revav")
.Description($"Returns a google reverse image search for someone's avatar. | `{Prefix}revav \"@SomeGuy\"")
.Description($"Returns a google reverse image search for someone's avatar. | `{Prefix}revav \"@SomeGuy\"`")
.Parameter("user", ParameterType.Unparsed)
.Do(async e =>
{
@ -502,7 +502,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
cgb.CreateCommand(Prefix + "av")
.Alias(Prefix + "avatar")
.Parameter("mention", ParameterType.Required)
.Description($"Shows a mentioned person's avatar. | `{Prefix}av @X`")
.Description($"Shows a mentioned person's avatar. | `{Prefix}av \"@SomeGuy\"`")
.Do(async e =>
{
var usr = e.Channel.FindUsers(e.GetArg("mention")).FirstOrDefault();

View File

@ -13,7 +13,7 @@ namespace NadekoBot.Modules.Translator
internal override void Init(CommandGroupBuilder cgb)
{
cgb.CreateCommand(Module.Prefix + "translangs")
.Description("List the valid languages for translation.")
.Description($"List the valid languages for translation. | `{Prefix}translangs` or `{Prefix}translangs language`")
.Parameter("search", ParameterType.Optional)
.Do(ListLanguagesFunc());
}

View File

@ -71,7 +71,7 @@ namespace NadekoBot.Modules.Trello
cgb.CreateCommand(Prefix + "bind")
.Description("Bind a trello bot to a single channel. " +
"You will receive notifications from your board when something is added or edited." +
$" | `{Prefix}bind [board_id]`")
$" **Bot Owner Only!**| `{Prefix}bind [board_id]`")
.Parameter("board_id", Discord.Commands.ParameterType.Required)
.Do(async e =>
{
@ -92,7 +92,7 @@ namespace NadekoBot.Modules.Trello
});
cgb.CreateCommand(Prefix + "unbind")
.Description("Unbinds a bot from the channel and board.")
.Description($"Unbinds a bot from the channel and board. **Bot Owner Only!**| `{Prefix}unbind`")
.Do(async e =>
{
if (!NadekoBot.IsOwner(e.User.Id)) return;
@ -106,7 +106,7 @@ namespace NadekoBot.Modules.Trello
cgb.CreateCommand(Prefix + "lists")
.Alias(Prefix + "list")
.Description("Lists all lists yo ;)")
.Description($"Lists all lists, yo ;) **Bot Owner Only!**| `{Prefix}list`")
.Do(async e =>
{
if (!NadekoBot.IsOwner(e.User.Id)) return;
@ -116,7 +116,7 @@ namespace NadekoBot.Modules.Trello
});
cgb.CreateCommand(Prefix + "cards")
.Description($"Lists all cards from the supplied list. You can supply either a name or an index. | `{Prefix}cards index`")
.Description($"Lists all cards from the supplied list. You can supply either a name or an index. **Bot Owner Only!**| `{Prefix}cards index`")
.Parameter("list_name", Discord.Commands.ParameterType.Unparsed)
.Do(async e =>
{

View File

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

View File

@ -88,7 +88,7 @@ namespace NadekoBot.Modules.Utility.Commands
.Description("Sends a message to you or a channel after certain amount of time. " +
"First argument is me/here/'channelname'. Second argument is time in a descending order (mo>w>d>h>m) example: 1w5d3h10m. " +
"Third argument is a (multiword)message. " +
" | `.remind me 1d5h Do something` or `.remind #general Start now!`")
$" | `{Prefix}remind me 1d5h Do something` or `{Prefix}remind #general Start now!`")
.Parameter("meorchannel", ParameterType.Required)
.Parameter("time", ParameterType.Required)
.Parameter("message", ParameterType.Unparsed)
@ -171,7 +171,7 @@ namespace NadekoBot.Modules.Utility.Commands
UserId = (long)e.User.Id,
ServerId = (long)e.Server.Id
};
DbHandler.Instance.InsertData(rem);
DbHandler.Instance.Connection.Insert(rem);
reminders.Add(StartNewReminder(rem));
@ -180,7 +180,7 @@ namespace NadekoBot.Modules.Utility.Commands
cgb.CreateCommand(Module.Prefix + "remindmsg")
.Description("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!**")
$" Message specified in the remind, %target% - target channel of the remind. **Bot Owner Only!** | `{Prefix}remindmsg do something else`")
.Parameter("msg", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.OwnerOnly())
.Do(async e =>

View File

@ -48,7 +48,7 @@ namespace NadekoBot.Modules.Utility
if (arr.Length == 0)
await e.Channel.SendMessage("Nobody. (not 100% sure)").ConfigureAwait(false);
else
await e.Channel.SendMessage("```xl\n" + string.Join("\n", arr.GroupBy(item => (i++) / 3).Select(ig => string.Concat(ig.Select(el => $"• {el,-35}")))) + "\n```").ConfigureAwait(false);
await e.Channel.SendMessage("```xl\n" + string.Join("\n", arr.GroupBy(item => (i++) / 3).Select(ig => string.Concat(ig.Select(el => $"• {el,-35}")))) + "\n```").ConfigureAwait(false);
});
cgb.CreateCommand(Prefix + "inrole")
@ -87,7 +87,7 @@ namespace NadekoBot.Modules.Utility
});
cgb.CreateCommand(Prefix + "checkmyperms")
.Description("Checks your userspecific permissions on this channel.")
.Description($"Checks your userspecific permissions on this channel. | `{Prefix}checkmyperms`")
.Do(async e =>
{
var output = "```\n";
@ -100,21 +100,21 @@ namespace NadekoBot.Modules.Utility
});
cgb.CreateCommand(Prefix + "stats")
.Description("Shows some basic stats for Nadeko.")
.Description($"Shows some basic stats for Nadeko. | `{Prefix}stats`")
.Do(async e =>
{
await e.Channel.SendMessage(await NadekoStats.Instance.GetStats()).ConfigureAwait(false);
});
cgb.CreateCommand(Prefix + "dysyd")
.Description("Shows some basic stats for Nadeko.")
.Description($"Shows some basic stats for Nadeko. | `{Prefix}dysyd`")
.Do(async e =>
{
await e.Channel.SendMessage((await NadekoStats.Instance.GetStats()).Matrix().TrimTo(1990)).ConfigureAwait(false);
});
cgb.CreateCommand(Prefix + "userid").Alias(Prefix + "uid")
.Description($"Shows user ID. | `{Prefix}uid` or `{Prefix}uid \"@SomeGuy\"")
.Description($"Shows user ID. | `{Prefix}uid` or `{Prefix}uid \"@SomeGuy\"`")
.Parameter("user", ParameterType.Unparsed)
.Do(async e =>
{
@ -134,7 +134,7 @@ namespace NadekoBot.Modules.Utility
.Do(async e => await e.Channel.SendMessage("This server's ID is " + e.Server.Id).ConfigureAwait(false));
cgb.CreateCommand(Prefix + "roles")
.Description("List all roles on this server or a single user if specified.")
.Description("List all roles on this server or a single user if specified. | `{Prefix}roles`")
.Parameter("user", ParameterType.Unparsed)
.Do(async e =>
{
@ -143,10 +143,10 @@ namespace NadekoBot.Modules.Utility
var usr = e.Server.FindUsers(e.GetArg("user")).FirstOrDefault();
if (usr == null) return;
await e.Channel.SendMessage($"`List of roles for **{usr.Name}**:` \n• " + string.Join("\n• ", usr.Roles)).ConfigureAwait(false);
await e.Channel.SendMessage($"`List of roles for **{usr.Name}**:` \n• " + string.Join("\n• ", usr.Roles)).ConfigureAwait(false);
return;
}
await e.Channel.SendMessage("`List of roles:` \n• " + string.Join("\n• ", e.Server.Roles)).ConfigureAwait(false);
await e.Channel.SendMessage("`List of roles:` \n• " + string.Join("\n• ", e.Server.Roles)).ConfigureAwait(false);
});

View File

@ -117,12 +117,12 @@ namespace NadekoBot
Client = new DiscordClient(new DiscordConfigBuilder()
{
MessageCacheSize = 10,
ConnectionTimeout = 120000,
ConnectionTimeout = 180000,
LogLevel = LogSeverity.Warning,
LogHandler = (s, e) =>
Console.WriteLine($"Severity: {e.Severity}" +
$"Message: {e.Message}" +
$"ExceptionMessage: {e.Exception?.Message ?? "-"}"),
$"ExceptionMessage: {e.Exception?.Message ?? "-"}" +
$"Message: {e.Message}"),
});
//create a command service
@ -197,7 +197,7 @@ namespace NadekoBot
return;
}
#if NADEKO_RELEASE
await Task.Delay(100000).ConfigureAwait(false);
await Task.Delay(150000).ConfigureAwait(false);
#else
await Task.Delay(1000).ConfigureAwait(false);
#endif

View File

@ -162,7 +162,6 @@
<HintPath>lib\ScaredFingers.UnitsConversion.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Drawing" />
<Reference Include="System.Net" />
<Reference Include="System.Net.Http.Formatting, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
@ -202,6 +201,8 @@
<Compile Include="Modules\Searches\Commands\OsuCommands.cs" />
<Compile Include="Modules\Searches\Commands\PokemonSearchCommands.cs" />
<Compile Include="Modules\Utility\UtilityModule.cs" />
<Compile Include="SQLite.cs" />
<Compile Include="_Models\DataModels\TestDataModel.cs" />
<Compile Include="_Models\DataModels\Incident.cs" />
<Compile Include="_Models\JSONModels\AnimeResult.cs" />
<Compile Include="_Models\JSONModels\Configuration.cs" />
@ -215,6 +216,7 @@
<Compile Include="Modules\Music\Classes\MusicControls.cs" />
<Compile Include="Modules\Music\Classes\PoopyBuffer.cs" />
<Compile Include="Modules\Music\Classes\Song.cs" />
<Compile Include="Modules\Music\Classes\SongBuffer.cs" />
<Compile Include="Modules\Music\Classes\SoundCloud.cs" />
<Compile Include="Modules\Permissions\Classes\PermissionChecker.cs" />
<Compile Include="Modules\Permissions\Classes\PermissionHelper.cs" />
@ -264,7 +266,6 @@
<Compile Include="Modules\Gambling\DrawCommand.cs" />
<Compile Include="Modules\Gambling\FlipCoinCommand.cs" />
<Compile Include="Modules\Help\Commands\HelpCommand.cs" />
<Compile Include="Modules\Administration\Commands\VoiceNotificationCommand.cs" />
<Compile Include="Modules\Administration\Commands\VoicePlusTextCommand.cs" />
<Compile Include="Modules\Administration\AdministrationModule.cs" />
<Compile Include="Modules\Conversations\Conversations.cs" />
@ -296,8 +297,6 @@
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="Classes\NadekoStats.cs" />
<Compile Include="SQLite.cs" />
<Compile Include="SQLiteAsync.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
@ -550,6 +549,13 @@
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\SQLitePCL.native.sqlite3.v110_xp.0.9.2\build\SQLitePCL.native.sqlite3.v110_xp.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\SQLitePCL.native.sqlite3.v110_xp.0.9.2\build\SQLitePCL.native.sqlite3.v110_xp.targets'))" />
</Target>
<Import Project="..\packages\SQLitePCL.native.sqlite3.v110_xp.0.9.2\build\SQLitePCL.native.sqlite3.v110_xp.targets" Condition="Exists('..\packages\SQLitePCL.native.sqlite3.v110_xp.0.9.2\build\SQLitePCL.native.sqlite3.v110_xp.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">

View File

@ -1,503 +0,0 @@
//
// Copyright (c) 2012 Krueger Systems, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
namespace SQLite
{
public partial class SQLiteAsyncConnection
{
SQLiteConnectionString _connectionString;
SQLiteOpenFlags _openFlags;
public SQLiteAsyncConnection(string databasePath, bool storeDateTimeAsTicks = false)
: this(databasePath, SQLiteOpenFlags.ReadWrite | SQLiteOpenFlags.Create, storeDateTimeAsTicks)
{
}
public SQLiteAsyncConnection(string databasePath, SQLiteOpenFlags openFlags, bool storeDateTimeAsTicks = false)
{
_openFlags = openFlags;
_connectionString = new SQLiteConnectionString(databasePath, storeDateTimeAsTicks);
}
SQLiteConnectionWithLock GetConnection ()
{
return SQLiteConnectionPool.Shared.GetConnection (_connectionString, _openFlags);
}
public Task<CreateTablesResult> CreateTableAsync<T> ()
where T : new ()
{
return CreateTablesAsync (typeof (T));
}
public Task<CreateTablesResult> CreateTablesAsync<T, T2> ()
where T : new ()
where T2 : new ()
{
return CreateTablesAsync (typeof (T), typeof (T2));
}
public Task<CreateTablesResult> CreateTablesAsync<T, T2, T3> ()
where T : new ()
where T2 : new ()
where T3 : new ()
{
return CreateTablesAsync (typeof (T), typeof (T2), typeof (T3));
}
public Task<CreateTablesResult> CreateTablesAsync<T, T2, T3, T4> ()
where T : new ()
where T2 : new ()
where T3 : new ()
where T4 : new ()
{
return CreateTablesAsync (typeof (T), typeof (T2), typeof (T3), typeof (T4));
}
public Task<CreateTablesResult> CreateTablesAsync<T, T2, T3, T4, T5> ()
where T : new ()
where T2 : new ()
where T3 : new ()
where T4 : new ()
where T5 : new ()
{
return CreateTablesAsync (typeof (T), typeof (T2), typeof (T3), typeof (T4), typeof (T5));
}
public Task<CreateTablesResult> CreateTablesAsync (params Type[] types)
{
return Task.Factory.StartNew (() => {
CreateTablesResult result = new CreateTablesResult ();
var conn = GetConnection ();
using (conn.Lock ()) {
foreach (Type type in types) {
int aResult = conn.CreateTable (type);
result.Results[type] = aResult;
}
}
return result;
});
}
public Task<int> DropTableAsync<T> ()
where T : new ()
{
return Task.Factory.StartNew (() => {
var conn = GetConnection ();
using (conn.Lock ()) {
return conn.DropTable<T> ();
}
});
}
public Task<int> InsertAsync (object item)
{
return Task.Factory.StartNew (() => {
var conn = GetConnection ();
using (conn.Lock ()) {
return conn.Insert (item);
}
});
}
public Task<int> UpdateAsync (object item)
{
return Task.Factory.StartNew (() => {
var conn = GetConnection ();
using (conn.Lock ()) {
return conn.Update (item);
}
});
}
public Task<int> DeleteAsync (object item)
{
return Task.Factory.StartNew (() => {
var conn = GetConnection ();
using (conn.Lock ()) {
return conn.Delete (item);
}
});
}
public Task<T> GetAsync<T>(object pk)
where T : new()
{
return Task.Factory.StartNew(() =>
{
var conn = GetConnection();
using (conn.Lock())
{
return conn.Get<T>(pk);
}
});
}
public Task<T> FindAsync<T> (object pk)
where T : new ()
{
return Task.Factory.StartNew (() => {
var conn = GetConnection ();
using (conn.Lock ()) {
return conn.Find<T> (pk);
}
});
}
public Task<T> GetAsync<T> (Expression<Func<T, bool>> predicate)
where T : new()
{
return Task.Factory.StartNew(() =>
{
var conn = GetConnection();
using (conn.Lock())
{
return conn.Get<T> (predicate);
}
});
}
public Task<T> FindAsync<T> (Expression<Func<T, bool>> predicate)
where T : new ()
{
return Task.Factory.StartNew (() => {
var conn = GetConnection ();
using (conn.Lock ()) {
return conn.Find<T> (predicate);
}
});
}
public Task<int> ExecuteAsync (string query, params object[] args)
{
return Task<int>.Factory.StartNew (() => {
var conn = GetConnection ();
using (conn.Lock ()) {
return conn.Execute (query, args);
}
});
}
public Task<int> InsertAllAsync (IEnumerable items)
{
return Task.Factory.StartNew (() => {
var conn = GetConnection ();
using (conn.Lock ()) {
return conn.InsertAll (items);
}
});
}
public Task<int> UpdateAllAsync (IEnumerable items)
{
return Task.Factory.StartNew (() => {
var conn = GetConnection ();
using (conn.Lock ()) {
return conn.UpdateAll (items);
}
});
}
[Obsolete("Will cause a deadlock if any call in action ends up in a different thread. Use RunInTransactionAsync(Action<SQLiteConnection>) instead.")]
public Task RunInTransactionAsync (Action<SQLiteAsyncConnection> action)
{
return Task.Factory.StartNew (() => {
var conn = this.GetConnection ();
using (conn.Lock ()) {
conn.BeginTransaction ();
try {
action (this);
conn.Commit ();
}
catch (Exception) {
conn.Rollback ();
throw;
}
}
});
}
public Task RunInTransactionAsync(Action<SQLiteConnection> action)
{
return Task.Factory.StartNew(() =>
{
var conn = this.GetConnection();
using (conn.Lock())
{
conn.BeginTransaction();
try
{
action(conn);
conn.Commit();
}
catch (Exception)
{
conn.Rollback();
throw;
}
}
});
}
public AsyncTableQuery<T> Table<T> ()
where T : new ()
{
//
// This isn't async as the underlying connection doesn't go out to the database
// until the query is performed. The Async methods are on the query iteself.
//
var conn = GetConnection ();
return new AsyncTableQuery<T> (conn.Table<T> ());
}
public Task<T> ExecuteScalarAsync<T> (string sql, params object[] args)
{
return Task<T>.Factory.StartNew (() => {
var conn = GetConnection ();
using (conn.Lock ()) {
var command = conn.CreateCommand (sql, args);
return command.ExecuteScalar<T> ();
}
});
}
public Task<List<T>> QueryAsync<T> (string sql, params object[] args)
where T : new ()
{
return Task<List<T>>.Factory.StartNew (() => {
var conn = GetConnection ();
using (conn.Lock ()) {
return conn.Query<T> (sql, args);
}
});
}
}
//
// TODO: Bind to AsyncConnection.GetConnection instead so that delayed
// execution can still work after a Pool.Reset.
//
public class AsyncTableQuery<T>
where T : new ()
{
TableQuery<T> _innerQuery;
public AsyncTableQuery (TableQuery<T> innerQuery)
{
_innerQuery = innerQuery;
}
public AsyncTableQuery<T> Where (Expression<Func<T, bool>> predExpr)
{
return new AsyncTableQuery<T> (_innerQuery.Where (predExpr));
}
public AsyncTableQuery<T> Skip (int n)
{
return new AsyncTableQuery<T> (_innerQuery.Skip (n));
}
public AsyncTableQuery<T> Take (int n)
{
return new AsyncTableQuery<T> (_innerQuery.Take (n));
}
public AsyncTableQuery<T> OrderBy<U> (Expression<Func<T, U>> orderExpr)
{
return new AsyncTableQuery<T> (_innerQuery.OrderBy<U> (orderExpr));
}
public AsyncTableQuery<T> OrderByDescending<U> (Expression<Func<T, U>> orderExpr)
{
return new AsyncTableQuery<T> (_innerQuery.OrderByDescending<U> (orderExpr));
}
public Task<List<T>> ToListAsync ()
{
return Task.Factory.StartNew (() => {
using (((SQLiteConnectionWithLock)_innerQuery.Connection).Lock ()) {
return _innerQuery.ToList ();
}
});
}
public Task<int> CountAsync ()
{
return Task.Factory.StartNew (() => {
using (((SQLiteConnectionWithLock)_innerQuery.Connection).Lock ()) {
return _innerQuery.Count ();
}
});
}
public Task<T> ElementAtAsync (int index)
{
return Task.Factory.StartNew (() => {
using (((SQLiteConnectionWithLock)_innerQuery.Connection).Lock ()) {
return _innerQuery.ElementAt (index);
}
});
}
public Task<T> FirstAsync ()
{
return Task<T>.Factory.StartNew(() => {
using (((SQLiteConnectionWithLock)_innerQuery.Connection).Lock ()) {
return _innerQuery.First ();
}
});
}
public Task<T> FirstOrDefaultAsync ()
{
return Task<T>.Factory.StartNew(() => {
using (((SQLiteConnectionWithLock)_innerQuery.Connection).Lock ()) {
return _innerQuery.FirstOrDefault ();
}
});
}
}
public class CreateTablesResult
{
public Dictionary<Type, int> Results { get; private set; }
internal CreateTablesResult ()
{
this.Results = new Dictionary<Type, int> ();
}
}
class SQLiteConnectionPool
{
class Entry
{
public SQLiteConnectionString ConnectionString { get; private set; }
public SQLiteConnectionWithLock Connection { get; private set; }
public Entry (SQLiteConnectionString connectionString, SQLiteOpenFlags openFlags)
{
ConnectionString = connectionString;
Connection = new SQLiteConnectionWithLock (connectionString, openFlags);
}
public void OnApplicationSuspended ()
{
Connection.Dispose ();
Connection = null;
}
}
readonly Dictionary<string, Entry> _entries = new Dictionary<string, Entry> ();
readonly object _entriesLock = new object ();
static readonly SQLiteConnectionPool _shared = new SQLiteConnectionPool ();
/// <summary>
/// Gets the singleton instance of the connection tool.
/// </summary>
public static SQLiteConnectionPool Shared
{
get
{
return _shared;
}
}
public SQLiteConnectionWithLock GetConnection (SQLiteConnectionString connectionString, SQLiteOpenFlags openFlags)
{
lock (_entriesLock) {
Entry entry;
string key = connectionString.ConnectionString;
if (!_entries.TryGetValue (key, out entry)) {
entry = new Entry (connectionString, openFlags);
_entries[key] = entry;
}
return entry.Connection;
}
}
/// <summary>
/// Closes all connections managed by this pool.
/// </summary>
public void Reset ()
{
lock (_entriesLock) {
foreach (var entry in _entries.Values) {
entry.OnApplicationSuspended ();
}
_entries.Clear ();
}
}
/// <summary>
/// Call this method when the application is suspended.
/// </summary>
/// <remarks>Behaviour here is to close any open connections.</remarks>
public void ApplicationSuspended ()
{
Reset ();
}
}
class SQLiteConnectionWithLock : SQLiteConnection
{
readonly object _lockPoint = new object ();
public SQLiteConnectionWithLock (SQLiteConnectionString connectionString, SQLiteOpenFlags openFlags)
: base (connectionString.DatabasePath, openFlags, connectionString.StoreDateTimeAsTicks)
{
}
public IDisposable Lock ()
{
return new LockWrapper (_lockPoint);
}
private class LockWrapper : IDisposable
{
object _lockPoint;
public LockWrapper (object lockPoint)
{
_lockPoint = lockPoint;
Monitor.Enter (_lockPoint);
}
public void Dispose ()
{
Monitor.Exit (_lockPoint);
}
}
}
}

View File

@ -0,0 +1,8 @@
namespace NadekoBot.DataModels
{
internal class TestDataModel : IDataModel
{
public long TestNumber { get; set; }
public string TestString { get; set; }
}
}

View File

@ -81,6 +81,15 @@ namespace NadekoBot.Classes.JSONModels
"https://cdn.discordapp.com/attachments/140007341880901632/156721724430352385/okawari_01_haruka_weird_mask.jpg",
"https://cdn.discordapp.com/attachments/140007341880901632/156721728763068417/mustache-best-girl.png"
} },
{"%mention% inv", new List<string>() {
"To invite your bot, click on this link -> <https://discordapp.com/oauth2/authorize?client_id=%target%&scope=bot&permissions=66186303>"
} },
{ "%mention% threaten", new List<string>() {
"You wanna die, %target%?"
} },
{ "%mention% archer", new List<string>() {
"http://i.imgur.com/Bha9NhL.jpg"
} }
};
@ -208,7 +217,8 @@ Nadeko Support Server: <https://discord.gg/0ehQwTK2RBjAxzEY>";
{
File.WriteAllText("data/config.json", JsonConvert.SerializeObject(NadekoBot.Config, Formatting.Indented));
}
finally {
finally
{
configLock.Release();
}
}

View File

@ -82,6 +82,15 @@
"https://cdn.discordapp.com/attachments/140007341880901632/156721715831898113/hqdefault.jpg",
"https://cdn.discordapp.com/attachments/140007341880901632/156721724430352385/okawari_01_haruka_weird_mask.jpg",
"https://cdn.discordapp.com/attachments/140007341880901632/156721728763068417/mustache-best-girl.png"
],
"%mention% inv": [
"To invite your bot, click on this link -> <https://discordapp.com/oauth2/authorize?client_id=%target%&scope=bot&permissions=66186303>"
],
"%mention% threaten": [
"You wanna die, %target%?"
],
"%mention% archer": [
"http://i.imgur.com/Bha9NhL.jpg"
]
},
"RotatingStatuses": [],

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -11,6 +11,11 @@
<package id="Newtonsoft.Json" version="8.0.3" targetFramework="net46" />
<package id="RestSharp" version="105.2.3" targetFramework="net452" />
<package id="sqlite-net" version="1.0.8" targetFramework="net452" />
<package id="SQLitePCL.bundle_green" version="0.9.2" targetFramework="net452" />
<package id="SQLitePCL.native.sqlite3.v110_xp" version="0.9.2" targetFramework="net452" />
<package id="SQLitePCL.plugin.sqlite3.net45" version="0.9.2" targetFramework="net452" />
<package id="SQLitePCL.raw" version="0.9.2" targetFramework="net452" />
<package id="System.Data.SQLite" version="1.0.102.0" targetFramework="net452" />
<package id="taglib" version="2.1.0.0" targetFramework="net452" />
<package id="VideoLibrary" version="1.3.3" targetFramework="net452" />
</packages>

View File

@ -1,8 +1,9 @@
![img](https://ci.appveyor.com/api/projects/status/gmu6b3ltc80hr3k9?svg=true)
[![Discord](https://discordapp.com/api/servers/117523346618318850/widget.png)](https://discord.gg/0ehQwTK2RBjAxzEY)
[![Documentation Status](https://readthedocs.org/projects/nadekobot/badge/?version=latest)](http://nadekobot.readthedocs.io/en/latest/?badge=latest)
# NadekoBot
## [Click here to invite nadeko to your discord server](https://discordapp.com/oauth2/authorize?client_id=170254782546575360&scope=bot&permissions=66186303)
## [Click here to invite Nadeko to your Discord server](https://discordapp.com/oauth2/authorize?client_id=170254782546575360&scope=bot&permissions=66186303)
## [Click here for a list of commands](https://github.com/Kwoth/NadekoBot/blob/master/commandlist.md)
## INSTRUCTIONS, FAQ ---> [Wiki](https://github.com/Kwoth/NadekoBot/wiki)

View File

@ -1,62 +1,63 @@
######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`
######You can donate on patreon: `https://patreon.com/nadekobot`
######or paypal: `nadekodiscordbot@gmail.com`
#NadekoBot List Of Commands
Version: `NadekoBot v0.9.6051.26856`
Version: `NadekoBot v0.9.6054.4837`
### Help
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'
`-hgit` | Generates the commandlist.md file. **Bot Owner Only!**
`-readme`, `-guide` | Sends a readme and a guide links to the channel.
`-donate`, `~donate` | Instructions for helping the project!
`-modules`, `.modules` | List all bot modules.
`-commands`, `.commands` | List all of the bot's commands from a certain module.
`-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`
`-readme`, `-guide` | Sends a readme and a guide links to the channel. | `-readme` or `-guide`
`-donate`, `~donate` | Instructions for helping the project! | `{Prefix}donate` or `~donate`
`-modules`, `.modules` | List all bot modules. | `{Prefix}modules` or `.modules`
`-commands`, `.commands` | List all of the bot's commands from a certain module. | `{Prefix}commands` or `.commands`
### Administration
Command and aliases | Description | Usage
----------------|--------------|-------
`.grdel` | Toggles automatic deletion of greet and bye messages.
`.greet` | Toggles anouncements on the current channel when someone joins the server.
`.greetmsg` | 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%.
`.bye` | Toggles anouncements on the current channel when someone leaves the server.
`.byemsg` | 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.
`.byepm` | Toggles whether the good bye 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.
`.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.
`.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.
`.grdel` | Toggles automatic deletion of greet and bye messages. | `.grdel`
`.greet` | Toggles anouncements on the current channel when someone joins the server. | `.greet`
`.greetmsg` | 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%.`
`.bye` | Toggles anouncements on the current channel when someone leaves the server. | `.bye`
`.byemsg` | 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.`
`.byepm` | Toggles whether the good bye messages will be sent in a PM or in the text channel. | `.byepm`
`.greetpm` | Toggles whether the greet messages will be sent in a PM or in the text channel. | `.greetpm`
`.spmom` | Toggles whether mentions of other offline users on your server will send a pm to them. | `.spmom`
`.logserver` | Toggles logging in this channel. Logs every message sent/deleted/edited on the server. **Bot Owner Only!** | `.logserver`
`.logignore` | Toggles whether the .logserver command ignores this channel. Useful if you have hidden admin channel and public log channel. | `.logignore`
`.userpresence` | Starts logging to this channel when someone from the server goes online/offline/idle. | `.userpresence`
`.voicepresence` | Toggles logging to this channel whenever someone joins or leaves a voice channel you are in right now. | `{Prefix}voicerpresence`
`.repeatinvoke`, `.repinv` | Immediately shows the repeat message and restarts the timer. | `{Prefix}repinv`
`.repeat` | Repeat a message every X minutes. If no parameters are specified, repeat is disabled. Requires manage messages. | `.repeat 5 Hello there`
`.rotateplaying`, `.ropl` | Toggles rotation of playing status of the dynamic strings you specified earlier.
`.addplaying`, `.adpl` | Adds a specified string to the list of playing strings to rotate. Supported placeholders: %servers%, %users%, %playing%, %queued%, %trivia%
`.listplaying`, `.lipl` | Lists all playing statuses with their corresponding number.
`.removeplaying`, `.repl`, `.rmpl` | Removes a playing string on a given number.
`.slowmode` | Toggles slow mode. When ON, users will be able to send only 1 message every 5 seconds.
`.cleanv+t`, `.cv+t` | Deletes all text channels ending in `-voice` for which voicechannels are not found. **Use at your own risk.**
`.voice+text`, `.v+t` | Creates a text channel for each voice channel only users in that voice channel can see.If you are server owner, keep in mind you will see them all the time regardless.
`.scsc` | Starts an instance of cross server channel. You will get a token as a DMthat other people will use to tune in to the same instance
`.jcsc` | Joins current channel to an instance of cross server channel using the token.
`.lcsc` | Leaves Cross server channel instance from this channel
`.rotateplaying`, `.ropl` | Toggles rotation of playing status of the dynamic strings you specified earlier. | `.ropl`
`.addplaying`, `.adpl` | Adds a specified string to the list of playing strings to rotate. Supported placeholders: %servers%, %users%, %playing%, %queued%, %trivia% | `.adpl`
`.listplaying`, `.lipl` | Lists all playing statuses with their corresponding number. | `.lipl`
`.removeplaying`, `.repl`, `.rmpl` | Removes a playing string on a given number. | `.rmpl`
`.slowmode` | Toggles slow mode. When ON, users will be able to send only 1 message every 5 seconds. | `.slowmode`
`.cleanv+t`, `.cv+t` | Deletes all text channels ending in `-voice` for which voicechannels are not found. **Use at your own risk.** | `.cleanv+t`
`.voice+text`, `.v+t` | Creates a text channel for each voice channel only users in that voice channel can see.If you are server owner, keep in mind you will see them all the time regardless. | `.voice+text`
`.scsc` | Starts an instance of cross server channel. You will get a token as a DM that other people will use to tune in to the same instance. | `.scsc`
`.jcsc` | Joins current channel to an instance of cross server channel using the token. | `.jcsc`
`.lcsc` | Leaves Cross server channel instance from this channel. | `.lcsc`
`.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.
`.lsar` | Lists all self-assignable roles.
`.togglexclsar`, `.tesar` | toggle whether the self-assigned roles should be exclusive
`.rsar` | Removes a specified role from the list of self-assignable roles. | `.rsar`
`.lsar` | Lists all self-assignable roles. | `.lsar`
`.togglexclsar`, `.tesar` | toggle whether the self-assigned roles should be exclusive | `.tesar`
`.iam` | Adds a role to you that you choose. Role must be on a list of self-assignable roles. | .iam Gamer
`.iamnot`, `.iamn` | Removes a role to you that you choose. Role must be on a list of self-assignable roles. | .iamn Gamer
`.addcustreact`, `.acr` | Add a custom reaction. Guide here: <https://github.com/Kwoth/NadekoBot/wiki/Custom-Reactions> **Bot Owner Only!** | .acr "hello" I love saying hello to %user%
`.listcustreact`, `.lcr` | Lists 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
`.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 custom reactions (paginated with 30 commands per page). Use 'all' instead of page number to get all custom reactions DM-ed to you. | `.lcr 1`
`.showcustreact`, `.scr` | Shows all possible responses from a single custom reaction. | `.scr %mention% bb`
`.editcustreact`, `.ecr` | Edits a custom reaction, arguments are custom reactions name, index to change, and a (multiword) message **Bot Owner Only** | `.ecr "%mention% disguise" 2 Test 123`
`.delcustreact`, `.dcr` | Deletes a custom reaction with given name (and index)
`.delcustreact`, `.dcr` | Deletes a custom reaction with given name (and index). | `.dcr index`
`.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`
`.listincidents`, `.lin` | List all UNREAD incidents and flags them as read.
`.listallincidents`, `.lain` | Sends you a file containing all incidents and flags them as read.
`.delmsgoncmd` | Toggles the automatic deletion of user's successful command message to prevent chat flood. Server Manager Only.
`.restart` | Restarts the bot. Might not work. **Bot Owner Only**
`.listincidents`, `.lin` | List all UNREAD incidents and flags them as read. | `.lin`
`.listallincidents`, `.lain` | Sends you a file containing all incidents and flags them as read. | `.lain`
`.delmsgoncmd` | Toggles the automatic deletion of user's successful command message to prevent chat flood. Server Manager Only. | `.delmsgoncmd`
`.restart` | Restarts the bot. Might not work. **Bot Owner Only** | `.restart`
`.setrole`, `.sr` | Sets a role for a given user. | `.sr @User Guest`
`.removerole`, `.rr` | Removes a role from a given user. | `.rr @User Admin`
`.renamerole`, `.renr` | Renames a role. Role you are renaming must be lower than bot's highest role. | `.renr "First role" SecondRole`
@ -76,15 +77,15 @@ Command and aliases | Description | Usage
`.creatxtchanl`, `.ctch` | Creates a new text channel with a given name. | `.ctch TextChannelName`
`.settopic`, `.st` | Sets a topic on the current channel. | `.st My new topic`
`.setchanlname`, `.schn` | Changed the name of the current channel.| `.schn NewName`
`.heap` | Shows allocated memory - **Bot Owner Only!**
`.heap` | Shows allocated memory - **Bot Owner Only!** | `.heap`
`.prune`, `.clr` | `.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`
`.die` | Shuts the bot down and notifies users about the restart. **Bot Owner Only!**
`.die` | Shuts the bot down and notifies users about the restart. **Bot Owner Only!** | `.die`
`.setname`, `.newnm` | Give the bot a new name. **Bot Owner Only!** | .newnm BotName
`.newavatar`, `.setavatar` | 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`
`.setgame` | Sets the bots game. **Bot Owner Only!** | `.setgame Playing with kwoth`
`.send` | 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!`
`.mentionrole`, `.menro` | Mentions every person from the provided role or roles (separated by a ',') on this server. Requires you to have mention everyone permission. | `.menro RoleName`
`.unstuck` | Clears the message queue. **Bot Owner Only!**
`.unstuck` | Clears the message queue. **Bot Owner Only!** | `.unstuck`
`.donators` | List of lovely people who donated to keep this project alive.
`.donadd` | Add a donator to the database. | `.donadd Donate Amount`
`.announce` | Sends a message to all servers' general channel bot is connected to.**Bot Owner Only!** | `.announce Useless spam`
@ -94,16 +95,16 @@ 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!`
`.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!**
`.serverinfo`, `.sinfo` | Shows info about the server the bot is on. If no channel is supplied, it defaults to current one. | .sinfo Some Server
`.channelinfo`, `.cinfo` | Shows info about the channel. If no channel is supplied, it defaults to current one. | .cinfo #some-channel
`.userinfo`, `.uinfo` | Shows info about the user. If no user is supplied, it defaults a user running the command. | .uinfo @SomeUser
`.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 do something else`
`.serverinfo`, `.sinfo` | Shows info about the server the bot is on. If no channel is supplied, it defaults to current one. | `.sinfo Some Server`
`.channelinfo`, `.cinfo` | Shows info about the channel. If no channel is supplied, it defaults to current one. | `.cinfo #some-channel`
`.userinfo`, `.uinfo` | Shows info about the user. If no user is supplied, it defaults a user running the command. | `.uinfo @SomeUser`
`.whoplays` | Shows a list of users who are playing the specified game. | `.whoplays Overwatch`
`.inrole` | Lists every person from the provided role or roles (separated by a ',') on this server. If the list is too long for 1 message, you must have Manage Messages permission. | `.inrole Role`
`.checkmyperms` | Checks your userspecific permissions on this channel.
`.stats` | Shows some basic stats for Nadeko.
`.dysyd` | Shows some basic stats for Nadeko.
`.userid`, `.uid` | Shows user ID. | `.uid` or `.uid "@SomeGuy"
`.checkmyperms` | Checks your userspecific permissions on this channel. | `.checkmyperms`
`.stats` | Shows some basic stats for Nadeko. | `.stats`
`.dysyd` | Shows some basic stats for Nadeko. | `.dysyd`
`.userid`, `.uid` | Shows user ID. | `.uid` or `.uid "@SomeGuy"`
`.channelid`, `.cid` | Shows current channel ID. | `.cid`
`.serverid`, `.sid` | Shows current server ID. | `.sid`
`.roles` | List all roles on this server or a single user if specified.
@ -119,12 +120,12 @@ Command and aliases | Description | Usage
`;rmvfilterword`, `;rfw` | Removes the word from the list of filtered words | ;rw poop
`;lstfilterwords`, `;lfw` | Shows a list of filtered words | ;lfw
`;srvrfilterwords`, `;sfw` | Enables or disables automatic deleting of messages containing forbidden words on the server. | ;sfw disable
`;permrole`, `;pr` | Sets a role which can change permissions. Or supply no parameters to find out the current one. Default one is 'Nadeko'.
`;permrole`, `;pr` | Sets a role which can change permissions. Or supply no parameters to find out the current one. Default one is 'Nadeko'. | `;pr role`
`;rolepermscopy`, `;rpc` | Copies BOT PERMISSIONS (not discord permissions) from one role to another. | `;rpc Some Role ~ Some other role`
`;chnlpermscopy`, `;cpc` | Copies BOT PERMISSIONS (not discord permissions) from one channel to another. | `;cpc Some Channel ~ Some other channel`
`;usrpermscopy`, `;upc` | Copies BOT PERMISSIONS (not discord permissions) from one role to another. | `;upc @SomeUser ~ @SomeOtherUser`
`;verbose`, `;v` | Sets whether to show when a command/module is blocked. | `;verbose true`
`;srvrperms`, `;sp` | Shows banned permissions for this server.
`;srvrperms`, `;sp` | Shows banned permissions for this server. | `;sp`
`;roleperms`, `;rp` | Shows banned permissions for a certain role. No argument means for everyone. | `;rp AwesomeRole`
`;chnlperms`, `;cp` | Shows banned permissions for a certain channel. No argument means for this channel. | `;cp #dev`
`;userperms`, `;up` | Shows banned permissions for a certain user. No argument means for yourself. | `;up Kwoth`
@ -157,48 +158,48 @@ Command and aliases | Description | Usage
`...` | Shows a random quote with a specified name. | `... abc`
`..qdel`, `..quotedelete` | Deletes all quotes with the specified keyword. You have to either be bot owner or the creator of the quote to delete it. | `..qdel abc`
`@BotName rip` | Shows a grave image of someone with a start year | @NadekoBot rip @Someone 2000
`@BotName die` | Works only for the owner. Shuts the bot down.
`@BotName do you love me` | Replies with positive answer only to the bot owner.
`@BotName how are you`, `@BotName how are you?` | Replies positive only if bot owner is online.
`@BotName fire` | Shows a unicode fire message. Optional parameter [x] tells her how many times to repeat the fire. | @NadekoBot fire [x]
`@BotName dump` | Dumps all of the invites it can to dump.txt.** Owner Only.**
`@BotName ab` | Try to get 'abalabahaha'
`@BotName die` | Works only for the owner. Shuts the bot down. | `@NadekoBot die`
`@BotName do you love me` | Replies with positive answer only to the bot owner. | `@NadekoBot do you love me`
`@BotName how are you`, `@BotName how are you?` | Replies positive only if bot owner is online. | `@NadekoBot how are you`
`@BotName fire` | Shows a unicode fire message. Optional parameter [x] tells her how many times to repeat the fire. | `@NadekoBot fire [x]`
`@BotName dump` | Dumps all of the invites it can to dump.txt.** Owner Only.** | `@NadekoBot dump`
`@BotName ab` | Try to get 'abalabahaha'| `@NadekoBot ab`
### Gambling
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]
`$shuffle`, `$sh` | Reshuffles all cards back into the deck.
`$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`
`$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
`$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
`$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`
`$race` | Starts a new animal race.
`$race` | Starts a new animal race. | `$race`
`$joinrace`, `$jr` | Joins a new race. You can specify an amount of flowers for betting (optional). You will get YourBet*(participants-1) back if you win. | `$jr` or `$jr 5`
`$raffle` | Prints a name and ID of a random user from the online list from the (optional) role. | `$raffle` or `$raffle RoleName
`$raffle` | Prints a name and ID of a random user from the online list from the (optional) role. | `$raffle` or `$raffle RoleName`
`$$$` | 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|`$give 1 "@SomeGuy"`
`$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 1 "@someguy"`
`$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` |
`$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` | Displays bot currency leaderboard | $lb
### Games
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`
`>tl` | Shows a current trivia leaderboard.
`>tq` | Quits current trivia after current question.
`>typestart` | Starts a typing contest.
`>typestop` | Stops a typing contest on the current channel.
`>typeadd` | Adds a new article to the typing contest. Owner only.
`>poll` | Creates a poll, only person who has manage server permission can do it. | >poll Question?;Answer1;Answ 2;A_3
`>pollend` | Stops active poll on this server and prints the results in this channel.
`>pick` | Picks a flower planted in this channel.
`>plant` | Spend a flower to plant it in this channel. (If bot is restarted or crashes, flower will be lost)
`>tl` | Shows a current trivia leaderboard. | `>tl`
`>tq` | Quits current trivia after current question. | `>tq`
`>typestart` | Starts a typing contest. | `>typestart`
`>typestop` | Stops a typing contest on the current channel. | `>typestop`
`>typeadd` | Adds a new article to the typing contest. Owner only. | `>typeadd wordswords`
`>poll` | Creates a poll, only person who has manage server permission can do it. | `>poll Question?;Answer1;Answ 2;A_3`
`>pollend` | Stops active poll on this server and prints the results in this channel. | `>pollend`
`>pick` | Picks a flower planted in this channel. | `>pick`
`>plant` | Spend a flower to plant it in this channel. (If bot is restarted or crashes, flower will be lost) | `>plant`
`>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`
`>8ball` | Ask the 8ball a yes/no question. | `>8ball should i do something`
`>rps` | Play a game of rocket paperclip scissors with Nadeko. | `>rps scissors`
@ -237,37 +238,37 @@ Command and aliases | Description | Usage
`!!load` | Loads a playlist under a certain name. | `!!load classical-1`
`!!playlists`, `!!pls` | Lists all playlists. Paginated. 20 per page. Default page is 0. | `!!pls 1`
`!!deleteplaylist`, `!!delpls` | Deletes a saved playlist. Only if you made it or if you are the bot owner. | `!!delpls animu-5`
`!!goto` | Goes to a specific time in seconds in a song. | !!goto 30
`!!goto` | Goes to a specific time in seconds in a song. | `!!goto 30`
`!!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
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
`~lolban` | Shows top 6 banned champions ordered by ban rate. Ban these champions and you will be Plat 5 in no time.
`~hitbox`, `~hb` | Notifies this channel when a certain user starts streaming. | ~hitbox SomeStreamer
`~twitch`, `~tw` | Notifies this channel when a certain user starts streaming. | ~twitch SomeStreamer
`~beam`, `~bm` | Notifies this channel when a certain user starts streaming. | ~beam SomeStreamer
`~checkhitbox`, `~chhb` | Checks if a certain user is streaming on the hitbox platform. | ~chhb SomeStreamer
`~checktwitch`, `~chtw` | Checks if a certain user is streaming on the twitch platform. | ~chtw SomeStreamer
`~checkbeam`, `~chbm` | Checks if a certain user is streaming on the beam platform. | ~chbm SomeStreamer
`~removestream`, `~rms` | Removes notifications of a certain streamer on this channel. | ~rms SomeGuy
`~liststreams`, `~ls` | Lists all streams you are following on this server. | ~ls
`~convert` | Convert quantities from>to. Like `~convert m>km 1000`
`~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`
`~hitbox`, `~hb` | Notifies this channel when a certain user starts streaming. | `~hitbox SomeStreamer`
`~twitch`, `~tw` | Notifies this channel when a certain user starts streaming. | `~twitch SomeStreamer`
`~beam`, `~bm` | Notifies this channel when a certain user starts streaming. | `~beam SomeStreamer`
`~checkhitbox`, `~chhb` | Checks if a certain user is streaming on the hitbox platform. | `~chhb SomeStreamer`
`~checktwitch`, `~chtw` | Checks if a certain user is streaming on the twitch platform. | `~chtw SomeStreamer`
`~checkbeam`, `~chbm` | Checks if a certain user is streaming on the beam platform. | `~chbm SomeStreamer`
`~removestream`, `~rms` | Removes notifications of a certain streamer on this channel. | `~rms SomeGuy`
`~liststreams`, `~ls` | Lists all streams you are following on this server. | `~ls`
`~convert` | Convert quantities from>to. | `~convert m>km 1000`
`~convertlist` | List of the convertable dimensions and currencies.
`~wowjoke` | Get one of Kwoth's penultimate WoW jokes.
`~wowjoke` | Get one of Kwoth's penultimate WoW jokes. | `~wowjoke`
`~calculate`, `~calc` | Evaluate a mathematical expression. | ~calc 1+1
`~osu` | Shows osu stats for a player. | `~osu Name` or `~osu Name taiko`
`~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
`~pokemon`, `~poke` | Searches for a pokemon.
`~pokemonability`, `~pokeab` | Searches for a pokemon ability.
`~memelist` | Pulls a list of memes you can use with `~memegen` from http://memegen.link/templates/
`~pokemon`, `~poke` | Searches for a pokemon. | `~poke Sylveon`
`~pokemonability`, `~pokeab` | Searches for a pokemon ability. | `~pokeab "water gun"`
`~memelist` | Pulls a list of memes you can use with `~memegen` from http://memegen.link/templates/ | `~memelist`
`~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`
`~yt` | Searches youtubes and shows the first result | `~yt query`
`~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. | `~aq aquerion evol`
`~imdb` | Queries imdb for movies or series, show first result. | `~imdb query`
`~mang`, `~manga`, `~mq` | Queries anilist for a manga and shows the first result. | `~mq query`
`~randomcat`, `~meow` | Shows a random cat image.
@ -279,13 +280,13 @@ Command and aliases | Description | Usage
`~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`
`~#` | Searches Tagdef.com for a hashtag. | `~# ff`
`~quote` | Shows a random quote.
`~catfact` | Shows a random catfact from <http://catfacts-api.appspot.com/api/facts>
`~yomama`, `~ym` | Shows a random joke from <http://api.yomomma.info/>
`~randjoke`, `~rj` | Shows a random joke from <http://tambal.azurewebsites.net/joke/random>
`~chucknorris`, `~cn` | Shows a random chucknorris joke from <http://tambal.azurewebsites.net/joke/random>
`~magicitem`, `~mi` | Shows a random magicitem from <https://1d4chan.org/wiki/List_of_/tg/%27s_magic_items>
`~revav` | Returns a google reverse image search for someone's avatar. | `~revav "@SomeGuy"
`~quote` | Shows a random quote. | `~quote`
`~catfact` | Shows a random catfact from <http://catfacts-api.appspot.com/api/facts> | `~catfact`
`~yomama`, `~ym` | Shows a random joke from <http://api.yomomma.info/> | `~ym`
`~randjoke`, `~rj` | Shows a random joke from <http://tambal.azurewebsites.net/joke/random> | `~rj`
`~chucknorris`, `~cn` | Shows a random chucknorris joke from <http://tambal.azurewebsites.net/joke/random> | `~cn`
`~magicitem`, `~mi` | Shows a random magicitem from <https://1d4chan.org/wiki/List_of_/tg/%27s_magic_items> | `~mi`
`~revav` | Returns a google reverse image search for someone's avatar. | `~revav "@SomeGuy"`
`~revimg` | Returns a google reverse image search for an image from a link. | `~revav Image link`
`~safebooru` | Shows a random image from safebooru with a given tag. Tag is optional but preffered. (multiple tags are appended with +) | `~safebooru yuri+kissing`
`~wiki` | Gives you back a wikipedia link | `~wiki query`
@ -301,15 +302,15 @@ Command and aliases | Description | Usage
`~gelbooru` | Shows a random hentai image from gelbooru with a given tag. Tag is optional but preffered. (multiple tags are appended with +) | `~gelbooru yuri+kissing`
`~rule34` | Shows a random image from rule34.xx with a given tag. Tag is optional but preffered. (multiple tags are appended with +) | `~rule34 yuri+kissing`
`~e621` | 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`
`~cp` | We all know where this will lead you to.
`~boobs` | Real adult content.
`~butts`, `~ass`, `~butt` | Real adult content.
`~cp` | We all know where this will lead you to. | `~cp`
`~boobs` | Real adult content. | `~boobs`
`~butts`, `~ass`, `~butt` | Real adult content. | `~butts` or `~ass`
### ClashOfClans
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
`,startwar`, `,sw` | Starts a war with a given number. | `,sw 1`
`,startwar`, `,sw` | Starts a war with a given number.
`,listwar`, `,lw` | Shows the active war claims by a number. Shows all wars in a short way if no number is specified. | ,lw [war_number] or ,lw
`,claim`, `,call`, `,c` | Claims a certain base from a certain war. You can supply a name in the third optional argument to claim in someone else's place. | ,call [war_number] [base_number] [optional_other_name]
`,claimfinish`, `,cf`, `,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]
@ -322,16 +323,16 @@ Command and aliases | Description | Usage
Command and aliases | Description | Usage
----------------|--------------|-------
`>attack` | Attacks a target with the given move. Use `>movelist` to see a list of moves your type can use. | `>attack "vine whip" @someguy`
`>movelist`, `>ml` | Lists the moves you are able to use
`>heal` | Heals someone. Revives those who fainted. Costs a NadekoFlower | >heal @someone
`>type` | Get the poketype of the target. | >type @someone
`>settype` | Set your poketype. Costs a NadekoFlower. | >settype fire
`>movelist`, `>ml` | Lists the moves you are able to use | `>ml`
`>heal` | Heals someone. Revives those who fainted. Costs a NadekoFlower | `>heal @someone`
`>type` | Get the poketype of the target. | `>type @someone`
`>settype` | Set your poketype. Costs a NadekoFlower. | `>settype fire`
### Translator
Command and aliases | Description | Usage
----------------|--------------|-------
`~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. | `{Prefix}translangs` or `{Prefix}translangs language`
### Customreactions
Command and aliases | Description | Usage

1
docs/index.rst Normal file
View File

@ -0,0 +1 @@
Hai, this will be docs of nakeda