Compare commits
23 Commits
Author | SHA1 | Date | |
---|---|---|---|
ce783c3f75 | |||
0589728f58 | |||
be9352bc03 | |||
af26fcfa5f | |||
|
7a73869a9f | ||
|
b1987be30c | ||
|
cdd5928028 | ||
c3a93b17dc | |||
|
55c4691933 | ||
|
cf2532af9a | ||
|
89a6adb389 | ||
|
b66ba51e0d | ||
|
f20ccd01f4 | ||
|
8842a86b30 | ||
|
0234df0844 | ||
|
68a92426c2 | ||
|
f5eaa4f335 | ||
|
7923c32323 | ||
|
cf5756e0a8 | ||
|
51f9ae9e3b | ||
|
eef5ad0c36 | ||
|
c3755055a1 | ||
|
494d8405b8 |
@ -1,7 +1,7 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.26730.3
|
||||
VisualStudioVersion = 15.0.26430.12
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{04929013-5BAB-42B0-B9B2-8F2BB8F16AF2}"
|
||||
EndProject
|
||||
@ -33,7 +33,4 @@ Global
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{45EC1473-C678-4857-A544-07DFE0D0B478} = {04929013-5BAB-42B0-B9B2-8F2BB8F16AF2}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {5F3F555C-855F-4BE8-B526-D062D3E8ACA4}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
@ -56,13 +56,13 @@ Follow this Detailed [Guide](http://discord.kongslien.net/guide.html).
|
||||
|
||||
###Question 12: I'm building NadekoBot from source, but I get hundreds of (namespace) errors without changing anything!?
|
||||
-----
|
||||
**Answer:** Using Visual Studio, you can solve these errors by going to `Tools` -> `NuGet Package Manager` -> `Manage NuGet Packages for Solution`. Go to the Installed tab, select the Packages that were missing (usually `Newtonsoft.json` and `RestSharp`) and install them for all projects
|
||||
**Answer:** Using Visual Studio, you can solve these errors by going to `Tools` -> `NuGet Package Manager` -> `Manage NuGet Packages for Solution`. Go to the Installed tab, select the Packages that were missing (usually `Newtonsoft.json` and `RestSharp`) and install them for all projects.
|
||||
|
||||
###Question 13: My bot has all permissions but it's still saying, "Failed to add roles. Bot has insufficient permissions". How do I fix this?
|
||||
----------
|
||||
**Answer:** Discord has added few new features and the roles now follows the role hierarchy which means you need to place your bot's role above every-other role your server has to fix the role hierarchy issue. [Here's](https://support.discordapp.com/hc/en-us/articles/214836687-Role-Management-101) a link to Discords role management 101.
|
||||
**Answer:** Discord has added a few new features and the roles now follow the role hierarchy, which means you need to place your bot's role above every other role on your server to fix the issue. [Here's](https://support.discordapp.com/hc/en-us/articles/214836687-Role-Management-101) a link to Discord's role management 101.
|
||||
|
||||
**Please Note:** *The bot can only set/add all roles below its own highest role. It can not assign it's "highest role" to anyone else.*
|
||||
**Please Note:** *The bot can only set/add all roles below its own highest role. It cannot assign its "highest role" to anyone else.*
|
||||
|
||||
###Question 14: I've broken permissions and am stuck, can I reset permissions?
|
||||
----------
|
||||
|
@ -1,9 +1,9 @@
|
||||
Permissions Overview
|
||||
===================
|
||||
Have you ever felt confused or even overwhelmed when trying to set Nadeko's permissions? In this guide we will be explaining how to use the
|
||||
permission commands correctly and even cover a few common questions! Every command we discuss here can be found in the [Commands List](http://nadekobot.readthedocs.io/en/1.0/Commands%20List/#permissions).
|
||||
permission commands correctly and even cover a few common questions! Every command we discuss here can be found in the [Commands List](http://nadekobot.readthedocs.io/en/latest/Commands%20List/#permissions).
|
||||
|
||||
**To see the old guide for versions 0.9 and below, see [here](http://nadekobot.readthedocs.io/en/latest/Permissions%20System/)**
|
||||
**To see the guide, [click here](http://nadekobot.readthedocs.io/en/latest/Permissions%20System/)**
|
||||
|
||||
Why do we use the Permissions Commands?
|
||||
------------------------------
|
||||
@ -15,11 +15,14 @@ With the permissions system it possible to restrict who can skip the current son
|
||||
|
||||
First Time Setup
|
||||
------------------
|
||||
To change permissions you **must** meet the following requirement:
|
||||
To change permissions you **must** meet the following requirements:
|
||||
|
||||
**Have the role specified by `.permrole` (By default, this is Nadeko)**
|
||||
**Be the owner of the server**
|
||||
|
||||
**If you are NOT the server owner, get the role specified by `.permrole` (By default, this is Nadeko)**
|
||||
|
||||
If you have an existing role called `Nadeko` but can't assign it to yourself, create a new role called `Nadeko` and assign that to yourself.
|
||||
![img0](https://i.imgur.com/5QKZqqy.gif)
|
||||
|
||||
If you would like to set a different role, such as `Admins`, to be the role required to edit permissions, do `.permrole Admins` (you must have the current permission role to be able to do this).
|
||||
|
||||
@ -35,7 +38,7 @@ To view this permissions chain, do `.listperms`, with the top of the chain being
|
||||
If you want to remove a permission from the chain of permissions, do `.removeperm X` to remove rule number X and similarly, do `.moveperm X Y` to move rule number X to number Y (moving, not swapping!).
|
||||
|
||||
As an example, if you wanted to enable NSFW for a certain role, say "Lewd", you could do `.rolemdl NSFW enable Lewd`.
|
||||
This adds the rule to the top of the permissions chain so even if the default `.sm NSFW disabled` rule exists, the "Lewd" role will be able to use the NSFW module.
|
||||
This adds the rule to the top of the permissions chain so even if the default `.sm NSFW disable` rule exists, the "Lewd" role will be able to use the NSFW module.
|
||||
|
||||
If you want the bot to notify users why they can't use a command or module, use `.verbose true` and Nadeko will tell you what rule is preventing the command.
|
||||
|
||||
|
@ -6,13 +6,13 @@ Prerequisites
|
||||
*Clone the repo*
|
||||
`git clone -b 1.4 https://github.com/Kwoth/NadekoBot`
|
||||
`cd NadekoBot/src/NadekoBot`
|
||||
Edit `credentials.json.` Read the JSON Exaplanations guide on the left if you don't know how to set it up
|
||||
Edit `credentials.json.` Read the [JSON Explanations](http://nadekobot.readthedocs.io/en/latest/JSON%20Explanations/) guide if you don't know how to set it up.
|
||||
|
||||
*run*
|
||||
`dotnet restore`
|
||||
`dotnet run -c Release`
|
||||
|
||||
*when you decide to updatein the future (might not work if you've made custom edits to the source, make sure you know how git works)*
|
||||
*when you decide to update in the future (might not work if you've made custom edits to the source, make sure you know how git works)*
|
||||
`git pull`
|
||||
`dotnet restore`
|
||||
`dotnet run -c Release`
|
||||
|
@ -1,30 +1,30 @@
|
||||
#### If you have NadekoBot 1.x on Windows
|
||||
|
||||
- Go to `NadekoBot\src\NadekoBot` and backup your `credentials.json` file; then go to `NadekoBot\src\NadekoBot\bin\Release\netcoreapp1.0` and backup your `data` folder.
|
||||
- Follow the [Windows Guide](http://nadekobot.readthedocs.io/en/latest/guides/Windows%20Guide/) and install the latest version of **NadekoBot**.
|
||||
- Paste your `credentials.json` file into the `C:\Program Files\NadekoBot\system` folder.
|
||||
- Paste your `data` folder into `C:\Program Files\NadekoBot\system` folder.
|
||||
- Navigate to your **old** `Nadeko` folder and copy your `credentials.json` file and the `data` folder.
|
||||
- Paste credentials into the **NadekoBot 1.4x+** `C:\Program Files\NadekoBot\system` folder.
|
||||
- Paste your **old** `Nadeko` data folder into **NadekoBot 1.4x+** `C:\Program Files\NadekoBot\system` folder.
|
||||
- If it asks you to overwrite files, it is fine to do so.
|
||||
- Next launch your **new** Nadeko as the guide describes, if it is not already running.
|
||||
|
||||
|
||||
#### If you are running Dockerised Nadeko
|
||||
|
||||
- Shutdown your existing container **docker stop nadeko**.
|
||||
- Shutdown your existing container `docker stop nadeko`.
|
||||
- Move you credentials and other files to another folder.
|
||||
- Delete your container **docker rm nadeko**.
|
||||
- Create a new container **docker create --name=nadeko -v /nadeko/:/root/nadeko uirel/nadeko:1.4**.
|
||||
- Start the container **docker start nadeko** wait for it to complain about lacking credentials.
|
||||
- Stop the container **docker stop nadeko** open the nadeko folder and replace the credentials, database and other files with your copies.
|
||||
- Restart the container **docker start nadeko**.
|
||||
- Delete your container `docker rm nadeko`.
|
||||
- Create a new container `docker create --name=nadeko -v /nadeko/:/root/nadeko uirel/nadeko:1.4`.
|
||||
- Start the container with `docker start nadeko`, and wait for it to complain about lacking credentials.
|
||||
- Stop the container, `docker stop nadeko`, open the `Nadeko` folder and replace the credentials, database and other files with your copies.
|
||||
- Restart the container `docker start nadeko`.
|
||||
|
||||
#### If you have NadekoBot 1.x on Linux or macOS
|
||||
|
||||
- Backup the `NadekoBot.db` from `NadekoBot/src/NadekoBot/bin/Release/netcoreapp1.0/data`
|
||||
- Backup the `credentials.json` from `NadekoBot/src/NadekoBot/`
|
||||
- **For MacOS Users Only:** download and install the latest version of [.NET Core SDK](https://www.microsoft.com/net/core#macos)
|
||||
- Backup the `NadekoBot.db` from `NadekoBot/src/NadekoBot/bin/Release/netcoreapp1.0/data`.
|
||||
- Backup the `credentials.json` from `NadekoBot/src/NadekoBot/`.
|
||||
- **For MacOS Users Only:** download and install the latest version of [.NET Core SDK](https://www.microsoft.com/net/core#macos).
|
||||
- Next, use the command `cd ~ && wget -N https://github.com/Kwoth/NadekoBot-BashScript/raw/1.4/linuxAIO.sh && bash linuxAIO.sh`
|
||||
- **For Ubuntu, Debian and CentOS Users Only:** use the option `4. Auto-Install Prerequisites` to install the latest version of .NET Core SDK.
|
||||
- Use option `1. Download NadekoBot` to update your NadekoBot to 1.4.x.
|
||||
- Use option `1. Download NadekoBot` to update your NadekoBot to 1.4+ version.
|
||||
- Next, just [run your NadekoBot.](http://nadekobot.readthedocs.io/en/latest/guides/Linux%20Guide/#running-nadekobot)
|
||||
- *NOTE: 1.4.x uses `NadekoBot.db` file from `NadekoBot/src/NadekoBot/bin/Release/netcoreapp1.1/data` folder.*
|
||||
- *NOTE: 1.4+ version uses `NadekoBot.db` file from `NadekoBot/src/NadekoBot/bin/Release/netcoreapp1.1/data` folder.*
|
||||
|
@ -1,3 +1,3 @@
|
||||
{
|
||||
"sdk": { "version": "2.0.0" }
|
||||
"sdk": { "version": "1.0.1" }
|
||||
}
|
@ -2,11 +2,12 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Services.Impl;
|
||||
|
||||
namespace NadekoBot.Common.Attributes
|
||||
{
|
||||
public class Aliases : AliasAttribute
|
||||
{
|
||||
public Aliases([CallerMemberName] string memberName = "") : base(Localization.LoadCommand(memberName.ToLowerInvariant()).Cmd.Split(' ').Skip(1).ToArray())
|
||||
public Aliases([CallerMemberName] string memberName = "") : base(Localization.LoadCommandString(memberName.ToLowerInvariant() + "_cmd").Split(' ').Skip(1).ToArray())
|
||||
{
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ namespace NadekoBot.Common.Attributes
|
||||
{
|
||||
public class Description : SummaryAttribute
|
||||
{
|
||||
public Description([CallerMemberName] string memberName="") : base(Localization.LoadCommand(memberName.ToLowerInvariant()).Desc)
|
||||
public Description([CallerMemberName] string memberName="") : base(Localization.LoadCommandString(memberName.ToLowerInvariant() + "_desc"))
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ namespace NadekoBot.Common.Attributes
|
||||
{
|
||||
public class NadekoCommand : CommandAttribute
|
||||
{
|
||||
public NadekoCommand([CallerMemberName] string memberName="") : base(Localization.LoadCommand(memberName.ToLowerInvariant()).Cmd)
|
||||
public NadekoCommand([CallerMemberName] string memberName="") : base(Localization.LoadCommandString(memberName.ToLowerInvariant() + "_cmd").Split(' ')[0])
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ namespace NadekoBot.Common.Attributes
|
||||
{
|
||||
public class Usage : RemarksAttribute
|
||||
{
|
||||
public Usage([CallerMemberName] string memberName="") : base(Localization.LoadCommand(memberName.ToLowerInvariant()).Usage)
|
||||
public Usage([CallerMemberName] string memberName="") : base(Localization.LoadCommandString(memberName.ToLowerInvariant()+"_usage"))
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -1,9 +0,0 @@
|
||||
namespace NadekoBot.Common
|
||||
{
|
||||
public class CommandData
|
||||
{
|
||||
public string Cmd { get; set; }
|
||||
public string Usage { get; set; }
|
||||
public string Desc { get; set; }
|
||||
}
|
||||
}
|
1949
src/NadekoBot/Migrations/20170913022654_total-xp.Designer.cs
generated
1949
src/NadekoBot/Migrations/20170913022654_total-xp.Designer.cs
generated
File diff suppressed because it is too large
Load Diff
@ -1,27 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace NadekoBot.Migrations
|
||||
{
|
||||
public partial class totalxp : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "TotalXp",
|
||||
table: "DiscordUser",
|
||||
nullable: false,
|
||||
defaultValue: 0);
|
||||
|
||||
migrationBuilder.Sql(MigrationQueries.TotalXp);
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "TotalXp",
|
||||
table: "DiscordUser");
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,25 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace NadekoBot.Migrations
|
||||
{
|
||||
public partial class clubadmins : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<bool>(
|
||||
name: "IsClubAdmin",
|
||||
table: "DiscordUser",
|
||||
nullable: false,
|
||||
defaultValue: false);
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "IsClubAdmin",
|
||||
table: "DiscordUser");
|
||||
}
|
||||
}
|
||||
}
|
@ -34,9 +34,5 @@ INSERT INTO DiscordUser
|
||||
FROM DiscordUser_tmp;
|
||||
|
||||
DROP TABLE DiscordUser_tmp;";
|
||||
public static string TotalXp { get; } =
|
||||
@"UPDATE DiscordUser
|
||||
SET TotalXp = ifnull((SELECT SUM(Xp) FROM UserXpStats WHERE UserId = DiscordUser.UserId), 0)";
|
||||
|
||||
}
|
||||
}
|
@ -462,18 +462,14 @@ namespace NadekoBot.Migrations
|
||||
|
||||
b.Property<string>("Discriminator");
|
||||
|
||||
b.Property<bool>("IsClubAdmin");
|
||||
|
||||
b.Property<DateTime>("LastLevelUp")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasDefaultValue(new DateTime(2017, 9, 15, 5, 48, 8, 660, DateTimeKind.Local));
|
||||
.HasDefaultValue(new DateTime(2017, 9, 11, 22, 0, 31, 236, DateTimeKind.Local));
|
||||
|
||||
b.Property<DateTime>("LastXpGain");
|
||||
|
||||
b.Property<int>("NotifyOnLevelUp");
|
||||
|
||||
b.Property<int>("TotalXp");
|
||||
|
||||
b.Property<ulong>("UserId");
|
||||
|
||||
b.Property<string>("Username");
|
||||
@ -1366,7 +1362,7 @@ namespace NadekoBot.Migrations
|
||||
|
||||
b.Property<DateTime>("LastLevelUp")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasDefaultValue(new DateTime(2017, 9, 15, 5, 48, 8, 665, DateTimeKind.Local));
|
||||
.HasDefaultValue(new DateTime(2017, 9, 11, 22, 0, 31, 238, DateTimeKind.Local));
|
||||
|
||||
b.Property<int>("NotifyOnLevelUp");
|
||||
|
||||
|
@ -30,9 +30,8 @@ namespace NadekoBot.Modules.Administration
|
||||
private readonly IImagesService _images;
|
||||
private readonly MusicService _music;
|
||||
private readonly IBotConfigProvider _bc;
|
||||
private readonly NadekoBot _bot;
|
||||
|
||||
public SelfCommands(DbService db, NadekoBot bot, DiscordSocketClient client,
|
||||
public SelfCommands(DbService db, DiscordSocketClient client,
|
||||
MusicService music, IImagesService images, IBotConfigProvider bc)
|
||||
{
|
||||
_db = db;
|
||||
@ -40,7 +39,6 @@ namespace NadekoBot.Modules.Administration
|
||||
_images = images;
|
||||
_music = music;
|
||||
_bc = bc;
|
||||
_bot = bot;
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -351,7 +349,7 @@ namespace NadekoBot.Modules.Administration
|
||||
[OwnerOnly]
|
||||
public async Task SetGame([Remainder] string game = null)
|
||||
{
|
||||
await _bot.SetGameAsync(game).ConfigureAwait(false);
|
||||
await _client.SetGameAsync(game).ConfigureAwait(false);
|
||||
|
||||
await ReplyConfirmLocalized("set_game").ConfigureAwait(false);
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ using NadekoBot.Modules.Music.Services;
|
||||
using NadekoBot.Services;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NLog;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Services
|
||||
{
|
||||
@ -17,7 +16,6 @@ namespace NadekoBot.Modules.Administration.Services
|
||||
private readonly DiscordSocketClient _client;
|
||||
private readonly MusicService _music;
|
||||
private readonly Logger _log;
|
||||
private readonly IDataCache _cache;
|
||||
private readonly Replacer _rep;
|
||||
private readonly DbService _db;
|
||||
private readonly IBotConfigProvider _bcp;
|
||||
@ -29,19 +27,13 @@ namespace NadekoBot.Modules.Administration.Services
|
||||
public int Index { get; set; }
|
||||
}
|
||||
|
||||
public PlayingRotateService(DiscordSocketClient client, IBotConfigProvider bcp,
|
||||
MusicService music, DbService db, IDataCache cache, NadekoBot bot)
|
||||
public PlayingRotateService(DiscordSocketClient client, IBotConfigProvider bcp, MusicService music, DbService db)
|
||||
{
|
||||
_client = client;
|
||||
_bcp = bcp;
|
||||
_music = music;
|
||||
_db = db;
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
_cache = cache;
|
||||
|
||||
if (client.ShardId == 0)
|
||||
{
|
||||
|
||||
_rep = new ReplacementBuilder()
|
||||
.WithClient(client)
|
||||
.WithStats(client)
|
||||
@ -68,10 +60,7 @@ namespace NadekoBot.Modules.Administration.Services
|
||||
|
||||
status = _rep.Replace(status);
|
||||
|
||||
try
|
||||
{
|
||||
await bot.SetGameAsync(status).ConfigureAwait(false);
|
||||
}
|
||||
try { await client.SetGameAsync(status).ConfigureAwait(false); }
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.Warn(ex);
|
||||
@ -84,5 +73,4 @@ namespace NadekoBot.Modules.Administration.Services
|
||||
}, new TimerState(), TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -58,7 +58,8 @@ namespace NadekoBot.Modules.CustomReactions
|
||||
|
||||
if (channel == null)
|
||||
{
|
||||
await _service.AddGcr(cr).ConfigureAwait(false);
|
||||
Array.Resize(ref _service.GlobalReactions, _service.GlobalReactions.Length + 1);
|
||||
_service.GlobalReactions[_service.GlobalReactions.Length - 1] = cr;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -236,7 +237,8 @@ namespace NadekoBot.Modules.CustomReactions
|
||||
if ((toDelete.GuildId == null || toDelete.GuildId == 0) && Context.Guild == null)
|
||||
{
|
||||
uow.CustomReactions.Remove(toDelete);
|
||||
await _service.DelGcr(toDelete.Id);
|
||||
//todo 91 i can dramatically improve performance of this, if Ids are ordered.
|
||||
_service.GlobalReactions = _service.GlobalReactions.Where(cr => cr?.Id != toDelete.Id).ToArray();
|
||||
success = true;
|
||||
}
|
||||
else if ((toDelete.GuildId != null && toDelete.GuildId != 0) && Context.Guild.Id == toDelete.GuildId)
|
||||
|
@ -15,7 +15,6 @@ using NadekoBot.Modules.CustomReactions.Extensions;
|
||||
using NadekoBot.Modules.Permissions.Common;
|
||||
using NadekoBot.Modules.Permissions.Services;
|
||||
using NadekoBot.Services.Impl;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace NadekoBot.Modules.CustomReactions.Services
|
||||
{
|
||||
@ -33,11 +32,9 @@ namespace NadekoBot.Modules.CustomReactions.Services
|
||||
private readonly CommandHandler _cmd;
|
||||
private readonly IBotConfigProvider _bc;
|
||||
private readonly NadekoStrings _strings;
|
||||
private readonly IDataCache _cache;
|
||||
|
||||
public CustomReactionsService(PermissionService perms, DbService db, NadekoStrings strings,
|
||||
DiscordSocketClient client, CommandHandler cmd, IBotConfigProvider bc, IUnitOfWork uow,
|
||||
IDataCache cache)
|
||||
DiscordSocketClient client, CommandHandler cmd, IBotConfigProvider bc, IUnitOfWork uow)
|
||||
{
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
_db = db;
|
||||
@ -46,38 +43,12 @@ namespace NadekoBot.Modules.CustomReactions.Services
|
||||
_cmd = cmd;
|
||||
_bc = bc;
|
||||
_strings = strings;
|
||||
_cache = cache;
|
||||
|
||||
var sub = _cache.Redis.GetSubscriber();
|
||||
sub.Subscribe("gcr.added", (ch, msg) =>
|
||||
{
|
||||
Array.Resize(ref GlobalReactions, GlobalReactions.Length + 1);
|
||||
GlobalReactions[GlobalReactions.Length - 1] = JsonConvert.DeserializeObject<CustomReaction>(msg);
|
||||
}, StackExchange.Redis.CommandFlags.FireAndForget);
|
||||
sub.Subscribe("gcr.deleted", (ch, msg) =>
|
||||
{
|
||||
var id = int.Parse(msg);
|
||||
GlobalReactions = GlobalReactions.Where(cr => cr?.Id != id).ToArray();
|
||||
}, StackExchange.Redis.CommandFlags.FireAndForget);
|
||||
|
||||
var items = uow.CustomReactions.GetAll();
|
||||
|
||||
GuildReactions = new ConcurrentDictionary<ulong, CustomReaction[]>(items.Where(g => g.GuildId != null && g.GuildId != 0).GroupBy(k => k.GuildId.Value).ToDictionary(g => g.Key, g => g.ToArray()));
|
||||
GlobalReactions = items.Where(g => g.GuildId == null || g.GuildId == 0).ToArray();
|
||||
}
|
||||
|
||||
public Task AddGcr(CustomReaction cr)
|
||||
{
|
||||
var sub = _cache.Redis.GetSubscriber();
|
||||
return sub.PublishAsync("gcr.added", JsonConvert.SerializeObject(cr));
|
||||
}
|
||||
|
||||
public Task DelGcr(int id)
|
||||
{
|
||||
var sub = _cache.Redis.GetSubscriber();
|
||||
return sub.PublishAsync("gcr.deleted", id);
|
||||
}
|
||||
|
||||
public void ClearStats() => ReactionStats.Clear();
|
||||
|
||||
public CustomReaction TryGetCustomReaction(IUserMessage umsg)
|
||||
|
@ -331,7 +331,7 @@ namespace NadekoBot.Modules.Gambling
|
||||
var embed = new EmbedBuilder().WithOkColor();
|
||||
|
||||
if (entry.Type == ShopEntryType.Role)
|
||||
return embed.AddField(efb => efb.WithName(GetText("name")).WithValue(GetText("shop_role", Format.Bold(Context.Guild.GetRole(entry.RoleId)?.Name ?? "MISSING_ROLE"))).WithIsInline(true))
|
||||
return embed.AddField(efb => efb.WithName(GetText("name")).WithValue(GetText("shop_role", Format.Bold(entry.RoleName))).WithIsInline(true))
|
||||
.AddField(efb => efb.WithName(GetText("price")).WithValue(entry.Price.ToString()).WithIsInline(true))
|
||||
.AddField(efb => efb.WithName(GetText("type")).WithValue(entry.Type.ToString()).WithIsInline(true));
|
||||
else if (entry.Type == ShopEntryType.List)
|
||||
@ -349,7 +349,7 @@ namespace NadekoBot.Modules.Gambling
|
||||
{
|
||||
if (entry.Type == ShopEntryType.Role)
|
||||
{
|
||||
return GetText("shop_role", Format.Bold(Context.Guild.GetRole(entry.RoleId)?.Name ?? "MISSING_ROLE"));
|
||||
return GetText("shop_role", Format.Bold(entry.RoleName));
|
||||
}
|
||||
else if (entry.Type == ShopEntryType.List)
|
||||
{
|
||||
|
@ -38,7 +38,7 @@ namespace NadekoBot.Modules.Games
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
public async Task EightBall([Remainder] string question = null)
|
||||
public async Task _8Ball([Remainder] string question = null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(question))
|
||||
return;
|
||||
|
@ -3,6 +3,7 @@ using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Music.Common
|
||||
{
|
||||
@ -17,16 +18,27 @@ namespace NadekoBot.Modules.Music.Common
|
||||
|
||||
public string SongUri { get; private set; }
|
||||
|
||||
//private volatile bool restart = false;
|
||||
|
||||
public SongBuffer(string songUri, string skipTo, bool isLocal)
|
||||
{
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
//_log.Warn(songUri);
|
||||
this.SongUri = songUri;
|
||||
this._isLocal = isLocal;
|
||||
|
||||
try
|
||||
{
|
||||
this.p = StartFFmpegProcess(SongUri, 0);
|
||||
var t = Task.Run(() =>
|
||||
{
|
||||
this.p.BeginErrorReadLine();
|
||||
this.p.ErrorDataReceived += P_ErrorDataReceived;
|
||||
this.p.WaitForExit();
|
||||
});
|
||||
|
||||
this._outStream = this.p.StandardOutput.BaseStream;
|
||||
|
||||
}
|
||||
catch (System.ComponentModel.Win32Exception)
|
||||
{
|
||||
@ -56,14 +68,113 @@ Check the guides for your platform on how to setup ffmpeg correctly:
|
||||
Arguments = args,
|
||||
UseShellExecute = false,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = false,
|
||||
RedirectStandardError = true,
|
||||
CreateNoWindow = true,
|
||||
});
|
||||
}
|
||||
|
||||
private void P_ErrorDataReceived(object sender, DataReceivedEventArgs e)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(e.Data))
|
||||
return;
|
||||
_log.Error(">>> " + e.Data);
|
||||
if (e.Data?.Contains("Error in the pull function") == true)
|
||||
{
|
||||
_log.Error("Ignore this.");
|
||||
//restart = true;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly object locker = new object();
|
||||
private readonly bool _isLocal;
|
||||
|
||||
public Task<bool> StartBuffering(CancellationToken cancelToken)
|
||||
{
|
||||
var toReturn = new TaskCompletionSource<bool>();
|
||||
var _ = Task.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
////int maxLoopsPerSec = 25;
|
||||
//var sw = Stopwatch.StartNew();
|
||||
////var delay = 1000 / maxLoopsPerSec;
|
||||
//int currentLoops = 0;
|
||||
//int _bytesSent = 0;
|
||||
//try
|
||||
//{
|
||||
// //do
|
||||
// //{
|
||||
// // if (restart)
|
||||
// // {
|
||||
// // var cur = _bytesSent / 3840 / (1000 / 20.0f);
|
||||
// // _log.Info("Restarting");
|
||||
// // try { this.p.StandardOutput.Dispose(); } catch { }
|
||||
// // try { this.p.Dispose(); } catch { }
|
||||
// // this.p = StartFFmpegProcess(SongUri, cur);
|
||||
// // }
|
||||
// // restart = false;
|
||||
// ++currentLoops;
|
||||
// byte[] buffer = new byte[readSize];
|
||||
// int bytesRead = 1;
|
||||
// while (!cancelToken.IsCancellationRequested && !this.p.HasExited)
|
||||
// {
|
||||
// bytesRead = await p.StandardOutput.BaseStream.ReadAsync(buffer, 0, readSize, cancelToken).ConfigureAwait(false);
|
||||
// _bytesSent += bytesRead;
|
||||
// if (bytesRead == 0)
|
||||
// break;
|
||||
// bool written;
|
||||
// do
|
||||
// {
|
||||
// lock (locker)
|
||||
// written = _outStream.Write(buffer, 0, bytesRead);
|
||||
// if (!written)
|
||||
// await Task.Delay(2000, cancelToken);
|
||||
// }
|
||||
// while (!written && !cancelToken.IsCancellationRequested);
|
||||
// lock (locker)
|
||||
// if (_outStream.Length > 200_000 || bytesRead == 0)
|
||||
// if (toReturn.TrySetResult(true))
|
||||
// _log.Info("Prebuffering finished in {0}", sw.Elapsed.TotalSeconds.ToString("F2"));
|
||||
|
||||
// //_log.Info(_outStream.Length);
|
||||
// await Task.Delay(10);
|
||||
// }
|
||||
// //if (cancelToken.IsCancellationRequested)
|
||||
// // _log.Info("Song canceled");
|
||||
// //else if (p.HasExited)
|
||||
// // _log.Info("Song buffered completely (FFmpeg exited)");
|
||||
// //else if (bytesRead == 0)
|
||||
// // _log.Info("Nothing read");
|
||||
// //}
|
||||
// //while (restart && !cancelToken.IsCancellationRequested);
|
||||
//return Task.CompletedTask;
|
||||
toReturn.TrySetResult(true);
|
||||
}
|
||||
catch (System.ComponentModel.Win32Exception)
|
||||
{
|
||||
_log.Error(@"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/OjKk8F
|
||||
Linux Guide: https://goo.gl/ShjCUo");
|
||||
}
|
||||
catch (OperationCanceledException) { }
|
||||
catch (InvalidOperationException) { } // when ffmpeg is disposed
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.Info(ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (toReturn.TrySetResult(false))
|
||||
_log.Info("Prebuffering failed");
|
||||
}
|
||||
}, cancelToken);
|
||||
|
||||
return toReturn.Task;
|
||||
}
|
||||
|
||||
public int Read(byte[] b, int offset, int toRead)
|
||||
{
|
||||
lock (locker)
|
||||
@ -93,3 +204,214 @@ Check the guides for your platform on how to setup ffmpeg correctly:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//namespace NadekoBot.Services.Music
|
||||
//{
|
||||
// /// <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 : Stream
|
||||
// {
|
||||
// public SongBuffer(MusicPlayer musicPlayer, string basename, SongInfo songInfo, int skipTo, int maxFileSize)
|
||||
// {
|
||||
// MusicPlayer = musicPlayer;
|
||||
// Basename = basename;
|
||||
// SongInfo = songInfo;
|
||||
// SkipTo = skipTo;
|
||||
// MaxFileSize = maxFileSize;
|
||||
// CurrentFileStream = new FileStream(this.GetNextFile(), FileMode.OpenOrCreate, FileAccess.Read, FileShare.Write);
|
||||
// _log = LogManager.GetCurrentClassLogger();
|
||||
// }
|
||||
|
||||
// MusicPlayer MusicPlayer { get; }
|
||||
|
||||
// private string Basename { get; }
|
||||
|
||||
// private SongInfo SongInfo { get; }
|
||||
|
||||
// private int SkipTo { get; }
|
||||
|
||||
// private int MaxFileSize { get; } = 2.MiB();
|
||||
|
||||
// private long FileNumber = -1;
|
||||
|
||||
// private long NextFileToRead = 0;
|
||||
|
||||
// public bool BufferingCompleted { get; private set; } = false;
|
||||
|
||||
// private ulong CurrentBufferSize = 0;
|
||||
|
||||
// private FileStream CurrentFileStream;
|
||||
// private Logger _log;
|
||||
|
||||
// public Task BufferSong(CancellationToken cancelToken) =>
|
||||
// Task.Run(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 -vn -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 >= MaxFileSize)
|
||||
// {
|
||||
// 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/OjKk8F
|
||||
// Linux Guide: https://goo.gl/ShjCUo");
|
||||
// Console.ForegroundColor = oldclr;
|
||||
// }
|
||||
// catch (Exception ex)
|
||||
// {
|
||||
// Console.WriteLine($"Buffering stopped: {ex.Message}");
|
||||
// }
|
||||
// finally
|
||||
// {
|
||||
// if (outStream != null)
|
||||
// outStream.Dispose();
|
||||
// if (p != null)
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// p.Kill();
|
||||
// }
|
||||
// catch { }
|
||||
// p.Dispose();
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
|
||||
// /// <summary>
|
||||
// /// Return the next file to read, and delete the old one
|
||||
// /// </summary>
|
||||
// /// <returns>Name of the file to read</returns>
|
||||
// private 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;
|
||||
// }
|
||||
|
||||
// private bool IsNextFileReady()
|
||||
// {
|
||||
// return NextFileToRead <= FileNumber;
|
||||
// }
|
||||
|
||||
// private void CleanFiles()
|
||||
// {
|
||||
// for (long i = NextFileToRead - 1; i <= FileNumber; i++)
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// File.Delete(Basename + "-" + i);
|
||||
// }
|
||||
// catch { }
|
||||
// }
|
||||
// }
|
||||
|
||||
// //Stream part
|
||||
|
||||
// public override bool CanRead => true;
|
||||
|
||||
// public override bool CanSeek => false;
|
||||
|
||||
// public override bool CanWrite => false;
|
||||
|
||||
// public override long Length => (long)CurrentBufferSize;
|
||||
|
||||
// public override long Position { get; set; } = 0;
|
||||
|
||||
// public override void Flush() { }
|
||||
|
||||
// public override int Read(byte[] buffer, int offset, int count)
|
||||
// {
|
||||
// int read = CurrentFileStream.Read(buffer, offset, count);
|
||||
// if (read < count)
|
||||
// {
|
||||
// if (!BufferingCompleted || IsNextFileReady())
|
||||
// {
|
||||
// CurrentFileStream.Dispose();
|
||||
// CurrentFileStream = new FileStream(GetNextFile(), FileMode.OpenOrCreate, FileAccess.Read, FileShare.Write);
|
||||
// read += CurrentFileStream.Read(buffer, read + offset, count - read);
|
||||
// }
|
||||
// if (read < count)
|
||||
// Array.Clear(buffer, read, count - read);
|
||||
// }
|
||||
// return read;
|
||||
// }
|
||||
|
||||
// public override long Seek(long offset, SeekOrigin origin)
|
||||
// {
|
||||
// throw new NotImplementedException();
|
||||
// }
|
||||
|
||||
// public override void SetLength(long value)
|
||||
// {
|
||||
// throw new NotImplementedException();
|
||||
// }
|
||||
|
||||
// public override void Write(byte[] buffer, int offset, int count)
|
||||
// {
|
||||
// throw new NotImplementedException();
|
||||
// }
|
||||
|
||||
// public new void Dispose()
|
||||
// {
|
||||
// CurrentFileStream.Dispose();
|
||||
// MusicPlayer.SongCancelSource.Cancel();
|
||||
// CleanFiles();
|
||||
// base.Dispose();
|
||||
// }
|
||||
// }
|
||||
//}
|
@ -16,13 +16,9 @@ using NadekoBot.Modules.NSFW.Exceptions;
|
||||
|
||||
namespace NadekoBot.Modules.NSFW
|
||||
{
|
||||
// thanks to halitalf for adding autoboob and autobutt features :D
|
||||
public class NSFW : NadekoTopLevelModule<SearchesService>
|
||||
{
|
||||
private static readonly ConcurrentDictionary<ulong, Timer> _autoHentaiTimers = new ConcurrentDictionary<ulong, Timer>();
|
||||
private static readonly ConcurrentDictionary<ulong, Timer> _autoBoobTimers = new ConcurrentDictionary<ulong, Timer>();
|
||||
private static readonly ConcurrentDictionary<ulong, Timer> _autoButtTimers = new ConcurrentDictionary<ulong, Timer>();
|
||||
|
||||
private static readonly ConcurrentHashSet<ulong> _hentaiBombBlacklist = new ConcurrentHashSet<ulong>();
|
||||
|
||||
private async Task InternalHentai(IMessageChannel channel, string tag, bool noError)
|
||||
@ -53,34 +49,10 @@ namespace NadekoBot.Modules.NSFW
|
||||
.WithDescription($"[{GetText("tag")}: {tag}]({img})"))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
private async Task InternalBoobs(IMessageChannel Channel)
|
||||
{
|
||||
try
|
||||
{
|
||||
JToken obj;
|
||||
obj = JArray.Parse(await _service.Http.GetStringAsync($"http://api.oboobs.ru/boobs/{new NadekoRandom().Next(0, 10330)}").ConfigureAwait(false))[0];
|
||||
await Channel.SendMessageAsync($"http://media.oboobs.ru/{obj["preview"]}").ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await Channel.SendErrorAsync(ex.Message).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task InternalButts(IMessageChannel Channel)
|
||||
{
|
||||
try
|
||||
{
|
||||
JToken obj;
|
||||
obj = JArray.Parse(await _service.Http.GetStringAsync($"http://api.obutts.ru/butts/{new NadekoRandom().Next(0, 4335)}").ConfigureAwait(false))[0];
|
||||
await Channel.SendMessageAsync($"http://media.obutts.ru/{obj["preview"]}").ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await Channel.SendErrorAsync(ex.Message).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
public Task Hentai([Remainder] string tag = null) =>
|
||||
InternalHentai(Context.Channel, tag, false);
|
||||
#if !GLOBAL_NADEKO
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireUserPermission(ChannelPermission.ManageMessages)]
|
||||
@ -93,7 +65,7 @@ namespace NadekoBot.Modules.NSFW
|
||||
if (!_autoHentaiTimers.TryRemove(Context.Channel.Id, out t)) return;
|
||||
|
||||
t.Change(Timeout.Infinite, Timeout.Infinite); //proper way to disable the timer
|
||||
await ReplyConfirmLocalized("stopped").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("autohentai_stopped").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -127,90 +99,8 @@ namespace NadekoBot.Modules.NSFW
|
||||
interval,
|
||||
string.Join(", ", tagsArr)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireUserPermission(ChannelPermission.ManageMessages)]
|
||||
public async Task AutoBoobs(int interval = 0)
|
||||
{
|
||||
Timer t;
|
||||
|
||||
if (interval == 0)
|
||||
{
|
||||
if (!_autoBoobTimers.TryRemove(Context.Channel.Id, out t)) return;
|
||||
|
||||
t.Change(Timeout.Infinite, Timeout.Infinite); //proper way to disable the timer
|
||||
await ReplyConfirmLocalized("stopped").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (interval < 20)
|
||||
return;
|
||||
|
||||
t = new Timer(async (state) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await InternalBoobs(Context.Channel).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}, null, interval * 1000, interval * 1000);
|
||||
|
||||
_autoBoobTimers.AddOrUpdate(Context.Channel.Id, t, (key, old) =>
|
||||
{
|
||||
old.Change(Timeout.Infinite, Timeout.Infinite);
|
||||
return t;
|
||||
});
|
||||
|
||||
await ReplyConfirmLocalized("started", interval).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireUserPermission(ChannelPermission.ManageMessages)]
|
||||
public async Task AutoButts(int interval = 0)
|
||||
{
|
||||
Timer t;
|
||||
|
||||
if (interval == 0)
|
||||
{
|
||||
if (!_autoButtTimers.TryRemove(Context.Channel.Id, out t)) return;
|
||||
|
||||
t.Change(Timeout.Infinite, Timeout.Infinite); //proper way to disable the timer
|
||||
await ReplyConfirmLocalized("stopped").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (interval < 20)
|
||||
return;
|
||||
|
||||
t = new Timer(async (state) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await InternalButts(Context.Channel).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}, null, interval * 1000, interval * 1000);
|
||||
|
||||
_autoButtTimers.AddOrUpdate(Context.Channel.Id, t, (key, old) =>
|
||||
{
|
||||
old.Change(Timeout.Infinite, Timeout.Infinite);
|
||||
return t;
|
||||
});
|
||||
|
||||
await ReplyConfirmLocalized("started", interval).ConfigureAwait(false);
|
||||
}
|
||||
#endif
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
public Task Hentai([Remainder] string tag = null) =>
|
||||
InternalHentai(Context.Channel, tag, false);
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
public async Task HentaiBomb([Remainder] string tag = null)
|
||||
{
|
||||
@ -309,7 +199,7 @@ namespace NadekoBot.Modules.NSFW
|
||||
tag = tag.Trim().ToLowerInvariant();
|
||||
var added = _service.ToggleBlacklistedTag(Context.Guild.Id, tag);
|
||||
|
||||
if (added)
|
||||
if(added)
|
||||
await ReplyConfirmLocalized("blacklisted_tag_add", tag).ConfigureAwait(false);
|
||||
else
|
||||
await ReplyConfirmLocalized("blacklisted_tag_remove", tag).ConfigureAwait(false);
|
||||
|
@ -135,11 +135,11 @@ namespace NadekoBot.Modules.Permissions.Services
|
||||
{
|
||||
var oldPrefixes = new[] { ".", ";", "!!", "!m", "!", "+", "-", "$", ">" };
|
||||
uow._context.Database.ExecuteSqlCommand(
|
||||
@"UPDATE Permissionv2
|
||||
$@"UPDATE {nameof(Permissionv2)}
|
||||
SET secondaryTargetName=trim(substr(secondaryTargetName, 3))
|
||||
WHERE secondaryTargetName LIKE '!!%' OR secondaryTargetName LIKE '!m%';
|
||||
|
||||
UPDATE Permissionv2
|
||||
UPDATE {nameof(Permissionv2)}
|
||||
SET secondaryTargetName=substr(secondaryTargetName, 2)
|
||||
WHERE secondaryTargetName LIKE '.%' OR
|
||||
secondaryTargetName LIKE '~%' OR
|
||||
|
@ -76,13 +76,11 @@ namespace NadekoBot.Modules.Searches.Common
|
||||
if (images.Length == 0)
|
||||
return null;
|
||||
var toReturn = images[_rng.Next(images.Length)];
|
||||
#if !GLOBAL_NADEKO
|
||||
foreach (var dledImg in images)
|
||||
{
|
||||
if(dledImg != toReturn)
|
||||
_cache.Add(dledImg);
|
||||
}
|
||||
#endif
|
||||
return toReturn;
|
||||
}
|
||||
}
|
||||
|
@ -43,16 +43,20 @@ namespace NadekoBot.Modules.Searches
|
||||
string response;
|
||||
response = await _service.Http.GetStringAsync($"http://api.openweathermap.org/data/2.5/weather?q={query}&appid=42cd627dd60debf25a5739e50a217d74&units=metric").ConfigureAwait(false);
|
||||
|
||||
string responsef;
|
||||
responsef = await _service.Http.GetStringAsync($"http://api.openweathermap.org/data/2.5/weather?q={query}&appid=42cd627dd60debf25a5739e50a217d74&units=imperial").ConfigureAwait(false);
|
||||
|
||||
var data = JsonConvert.DeserializeObject<WeatherData>(response);
|
||||
var dataf = JsonConvert.DeserializeObject<WeatherData>(responsef);
|
||||
|
||||
var embed = new EmbedBuilder()
|
||||
.AddField(fb => fb.WithName("🌍 " + Format.Bold(GetText("location"))).WithValue($"[{data.Name + ", " + data.Sys.Country}](https://openweathermap.org/city/{data.Id})").WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("📏 " + Format.Bold(GetText("latlong"))).WithValue($"{data.Coord.Lat}, {data.Coord.Lon}").WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("☁ " + Format.Bold(GetText("condition"))).WithValue(string.Join(", ", data.Weather.Select(w => w.Main))).WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("😓 " + Format.Bold(GetText("humidity"))).WithValue($"{data.Main.Humidity}%").WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("💨 " + Format.Bold(GetText("wind_speed"))).WithValue(data.Wind.Speed + " m/s").WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("🌡 " + Format.Bold(GetText("temperature"))).WithValue(data.Main.Temp + "°C").WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("🔆 " + Format.Bold(GetText("min_max"))).WithValue($"{data.Main.TempMin}°C - {data.Main.TempMax}°C").WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("💨 " + Format.Bold(GetText("wind_speed"))).WithValue(data.Wind.Speed + " m/s" + " / " + dataf.Wind.Speed + " mph").WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("🌡 " + Format.Bold(GetText("temperature"))).WithValue(data.Main.Temp + "°C" + " / " + dataf.Main.Temp + "°F").WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("🔆 " + Format.Bold(GetText("min_max"))).WithValue($"{data.Main.TempMin}°C - {data.Main.TempMax}°C" + "\n" + $"{dataf.Main.TempMin}°F - {dataf.Main.TempMax}°F").WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("🌄 " + Format.Bold(GetText("sunrise"))).WithValue($"{data.Sys.Sunrise.ToUnixTimestamp():HH:mm} UTC").WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("🌇 " + Format.Bold(GetText("sunset"))).WithValue($"{data.Sys.Sunset.ToUnixTimestamp():HH:mm} UTC").WithIsInline(true))
|
||||
.WithOkColor()
|
||||
|
@ -11,14 +11,10 @@ namespace NadekoBot.Modules.Searches.Services
|
||||
public class AnimeSearchService : INService
|
||||
{
|
||||
private readonly Logger _log;
|
||||
private readonly IDataCache _cache;
|
||||
private readonly HttpClient _http;
|
||||
|
||||
public AnimeSearchService(IDataCache cache)
|
||||
public AnimeSearchService()
|
||||
{
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
_cache = cache;
|
||||
_http = new HttpClient();
|
||||
}
|
||||
|
||||
public async Task<AnimeResult> GetAnimeData(string query)
|
||||
@ -29,16 +25,11 @@ namespace NadekoBot.Modules.Searches.Services
|
||||
{
|
||||
|
||||
var link = "https://aniapi.nadekobot.me/anime/" + Uri.EscapeDataString(query.Replace("/", " "));
|
||||
link = link.ToLowerInvariant();
|
||||
var (ok, data) = await _cache.TryGetAnimeDataAsync(link).ConfigureAwait(false);
|
||||
if (!ok)
|
||||
using (var http = new HttpClient())
|
||||
{
|
||||
data = await _http.GetStringAsync(link).ConfigureAwait(false);
|
||||
await _cache.SetAnimeDataAsync(link, data).ConfigureAwait(false);
|
||||
var res = await http.GetStringAsync(link).ConfigureAwait(false);
|
||||
return JsonConvert.DeserializeObject<AnimeResult>(res);
|
||||
}
|
||||
|
||||
|
||||
return JsonConvert.DeserializeObject<AnimeResult>(data);
|
||||
}
|
||||
catch
|
||||
{
|
||||
@ -54,16 +45,11 @@ namespace NadekoBot.Modules.Searches.Services
|
||||
{
|
||||
|
||||
var link = "https://aniapi.nadekobot.me/manga/" + Uri.EscapeDataString(query.Replace("/", " "));
|
||||
link = link.ToLowerInvariant();
|
||||
var (ok, data) = await _cache.TryGetAnimeDataAsync(link).ConfigureAwait(false);
|
||||
if (!ok)
|
||||
using (var http = new HttpClient())
|
||||
{
|
||||
data = await _http.GetStringAsync(link).ConfigureAwait(false);
|
||||
await _cache.SetAnimeDataAsync(link, data).ConfigureAwait(false);
|
||||
var res = await http.GetStringAsync(link).ConfigureAwait(false);
|
||||
return JsonConvert.DeserializeObject<MangaResult>(res);
|
||||
}
|
||||
|
||||
|
||||
return JsonConvert.DeserializeObject<MangaResult>(data);
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
@ -26,27 +26,6 @@ namespace NadekoBot.Modules.Xp
|
||||
_client = client;
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
public async Task ClubAdmin([Remainder]IUser toAdmin)
|
||||
{
|
||||
bool admin;
|
||||
try
|
||||
{
|
||||
admin = _service.ToggleAdmin(Context.User, toAdmin);
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
await ReplyErrorLocalized("club_admin_error").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if(admin)
|
||||
await ReplyConfirmLocalized("club_admin_add", Format.Bold(toAdmin.ToString())).ConfigureAwait(false);
|
||||
else
|
||||
await ReplyConfirmLocalized("club_admin_remove", Format.Bold(toAdmin.ToString())).ConfigureAwait(false);
|
||||
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
public async Task ClubCreate([Remainder]string clubName)
|
||||
{
|
||||
@ -118,14 +97,7 @@ namespace NadekoBot.Modules.Xp
|
||||
.AddField("Level Req.", club.MinimumLevelReq.ToString(), true)
|
||||
.AddField("Members", string.Join("\n", club.Users
|
||||
.Skip(page * 10)
|
||||
.Take(10)
|
||||
.OrderByDescending(x => x.IsClubAdmin)
|
||||
.Select(x =>
|
||||
{
|
||||
if (x.IsClubAdmin)
|
||||
return x.ToString() + "⭐";
|
||||
return x.ToString();
|
||||
})), false);
|
||||
.Take(10)), false);
|
||||
|
||||
if (Uri.IsWellFormedUriString(club.ImageUrl, UriKind.Absolute))
|
||||
return embed.WithThumbnailUrl(club.ImageUrl);
|
||||
@ -140,7 +112,7 @@ namespace NadekoBot.Modules.Xp
|
||||
if (--page < 0)
|
||||
return Task.CompletedTask;
|
||||
|
||||
var club = _service.GetClubWithBansAndApplications(Context.User.Id);
|
||||
var club = _service.GetBansAndApplications(Context.User.Id);
|
||||
if (club == null)
|
||||
return ReplyErrorLocalized("club_not_exists");
|
||||
|
||||
@ -159,8 +131,7 @@ namespace NadekoBot.Modules.Xp
|
||||
|
||||
return new EmbedBuilder()
|
||||
.WithTitle(GetText("club_bans_for", club.ToString()))
|
||||
.WithDescription(toShow)
|
||||
.WithOkColor();
|
||||
.WithDescription(toShow);
|
||||
|
||||
}, bans.Length / 10);
|
||||
}
|
||||
@ -172,11 +143,11 @@ namespace NadekoBot.Modules.Xp
|
||||
if (--page < 0)
|
||||
return Task.CompletedTask;
|
||||
|
||||
var club = _service.GetClubWithBansAndApplications(Context.User.Id);
|
||||
var club = _service.GetBansAndApplications(Context.User.Id);
|
||||
if (club == null)
|
||||
return ReplyErrorLocalized("club_not_exists");
|
||||
|
||||
var apps = club
|
||||
var bans = club
|
||||
.Applicants
|
||||
.Select(x => x.User)
|
||||
.ToArray();
|
||||
@ -184,17 +155,16 @@ namespace NadekoBot.Modules.Xp
|
||||
return Context.Channel.SendPaginatedConfirmAsync(_client, page,
|
||||
curPage =>
|
||||
{
|
||||
var toShow = string.Join("\n", apps
|
||||
var toShow = string.Join("\n", bans
|
||||
.Skip(page * 10)
|
||||
.Take(10)
|
||||
.Select(x => x.ToString()));
|
||||
|
||||
return new EmbedBuilder()
|
||||
.WithTitle(GetText("club_apps_for", club.ToString()))
|
||||
.WithDescription(toShow)
|
||||
.WithOkColor();
|
||||
.WithDescription(toShow);
|
||||
|
||||
}, apps.Length / 10);
|
||||
}, bans.Length / 10);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -312,7 +282,7 @@ namespace NadekoBot.Modules.Xp
|
||||
}
|
||||
else
|
||||
{
|
||||
await ReplyErrorLocalized("club_disband_error").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("club_disaband_error").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,11 +27,10 @@ namespace NadekoBot.Modules.Xp.Services
|
||||
{
|
||||
var du = uow.DiscordUsers.GetOrCreate(user);
|
||||
uow._context.SaveChanges();
|
||||
var xp = new LevelStats(du.TotalXp);
|
||||
var xp = new LevelStats(uow.Xp.GetTotalUserXp(user.Id));
|
||||
|
||||
if (xp.Level >= 5 && du.Club == null)
|
||||
{
|
||||
du.IsClubAdmin = true;
|
||||
du.Club = new ClubInfo()
|
||||
{
|
||||
Name = clubName,
|
||||
@ -53,27 +52,6 @@ namespace NadekoBot.Modules.Xp.Services
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool ToggleAdmin(IUser owner, IUser toAdmin)
|
||||
{
|
||||
bool newState;
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var club = uow.Clubs.GetByOwner(owner.Id);
|
||||
var adminUser = uow.DiscordUsers.GetOrCreate(toAdmin);
|
||||
|
||||
if (club.OwnerId == adminUser.Id)
|
||||
return true;
|
||||
|
||||
if (club == null || club.Owner.UserId != owner.Id ||
|
||||
!club.Users.Contains(adminUser))
|
||||
throw new InvalidOperationException();
|
||||
|
||||
newState = adminUser.IsClubAdmin = !adminUser.IsClubAdmin;
|
||||
uow.Complete();
|
||||
}
|
||||
return newState;
|
||||
}
|
||||
|
||||
public ClubInfo GetClubByMember(IUser user)
|
||||
{
|
||||
using (var uow = _db.UnitOfWork)
|
||||
@ -129,7 +107,7 @@ namespace NadekoBot.Modules.Xp.Services
|
||||
uow._context.SaveChanges();
|
||||
|
||||
if (du.Club != null
|
||||
|| new LevelStats(du.TotalXp).Level < club.MinimumLevelReq
|
||||
|| new LevelStats(uow.Xp.GetTotalUserXp(user.Id)).Level < club.MinimumLevelReq
|
||||
|| club.Bans.Any(x => x.UserId == du.Id)
|
||||
|| club.Applicants.Any(x => x.UserId == du.Id))
|
||||
{
|
||||
@ -156,7 +134,11 @@ namespace NadekoBot.Modules.Xp.Services
|
||||
discordUser = null;
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
var club = uow.Clubs.GetByOwnerOrAdmin(clubOwnerUserId);
|
||||
var club = uow.Clubs.GetByOwner(clubOwnerUserId,
|
||||
set => set.Include(x => x.Applicants)
|
||||
.ThenInclude(x => x.Club)
|
||||
.Include(x => x.Applicants)
|
||||
.ThenInclude(x => x.User));
|
||||
if (club == null)
|
||||
return false;
|
||||
|
||||
@ -165,7 +147,6 @@ namespace NadekoBot.Modules.Xp.Services
|
||||
return false;
|
||||
|
||||
applicant.User.Club = club;
|
||||
applicant.User.IsClubAdmin = false;
|
||||
club.Applicants.Remove(applicant);
|
||||
|
||||
//remove that user's all other applications
|
||||
@ -178,11 +159,15 @@ namespace NadekoBot.Modules.Xp.Services
|
||||
return true;
|
||||
}
|
||||
|
||||
public ClubInfo GetClubWithBansAndApplications(ulong ownerUserId)
|
||||
public ClubInfo GetBansAndApplications(ulong ownerUserId)
|
||||
{
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
return uow.Clubs.GetByOwnerOrAdmin(ownerUserId);
|
||||
return uow.Clubs.GetByOwner(ownerUserId,
|
||||
x => x.Include(y => y.Bans)
|
||||
.ThenInclude(y => y.User)
|
||||
.Include(y => y.Applicants)
|
||||
.ThenInclude(y => y.User));
|
||||
}
|
||||
}
|
||||
|
||||
@ -195,7 +180,6 @@ namespace NadekoBot.Modules.Xp.Services
|
||||
return false;
|
||||
|
||||
du.Club = null;
|
||||
du.IsClubAdmin = false;
|
||||
uow.Complete();
|
||||
}
|
||||
return true;
|
||||
@ -237,7 +221,9 @@ namespace NadekoBot.Modules.Xp.Services
|
||||
{
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
club = uow.Clubs.GetByOwnerOrAdmin(ownerUserId);
|
||||
club = uow.Clubs.GetByOwner(ownerUserId,
|
||||
set => set.Include(x => x.Applicants)
|
||||
.ThenInclude(x => x.User));
|
||||
if (club == null)
|
||||
return false;
|
||||
|
||||
@ -270,7 +256,9 @@ namespace NadekoBot.Modules.Xp.Services
|
||||
{
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
club = uow.Clubs.GetByOwnerOrAdmin(ownerUserId);
|
||||
club = uow.Clubs.GetByOwner(ownerUserId,
|
||||
set => set.Include(x => x.Bans)
|
||||
.ThenInclude(x => x.User));
|
||||
if (club == null)
|
||||
return false;
|
||||
|
||||
@ -289,7 +277,7 @@ namespace NadekoBot.Modules.Xp.Services
|
||||
{
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
club = uow.Clubs.GetByOwnerOrAdmin(ownerUserId);
|
||||
club = uow.Clubs.GetByOwner(ownerUserId);
|
||||
if (club == null)
|
||||
return false;
|
||||
|
||||
|
@ -36,7 +36,6 @@ namespace NadekoBot.Modules.Xp.Services
|
||||
private readonly IImagesService _images;
|
||||
private readonly Logger _log;
|
||||
private readonly NadekoStrings _strings;
|
||||
private readonly IDataCache _cache;
|
||||
private readonly FontCollection _fonts = new FontCollection();
|
||||
public const int XP_REQUIRED_LVL_1 = 36;
|
||||
|
||||
@ -55,6 +54,9 @@ namespace NadekoBot.Modules.Xp.Services
|
||||
private readonly ConcurrentQueue<UserCacheItem> _addMessageXp
|
||||
= new ConcurrentQueue<UserCacheItem>();
|
||||
|
||||
private readonly ConcurrentDictionary<string, byte[]> _imageStreams
|
||||
= new ConcurrentDictionary<string, byte[]>();
|
||||
|
||||
private readonly Timer updateXpTimer;
|
||||
private readonly HttpClient http = new HttpClient();
|
||||
private FontFamily _usernameFontFamily;
|
||||
@ -67,7 +69,7 @@ namespace NadekoBot.Modules.Xp.Services
|
||||
|
||||
public XpService(CommandHandler cmd, IBotConfigProvider bc,
|
||||
IEnumerable<GuildConfig> allGuildConfigs, IImagesService images,
|
||||
DbService db, NadekoStrings strings, IDataCache cache)
|
||||
DbService db, NadekoStrings strings)
|
||||
{
|
||||
_db = db;
|
||||
_cmd = cmd;
|
||||
@ -75,7 +77,6 @@ namespace NadekoBot.Modules.Xp.Services
|
||||
_images = images;
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
_strings = strings;
|
||||
_cache = cache;
|
||||
|
||||
//load settings
|
||||
allGuildConfigs = allGuildConfigs.Where(x => x.XpSettings != null);
|
||||
@ -144,13 +145,12 @@ namespace NadekoBot.Modules.Xp.Services
|
||||
|
||||
du.LastXpGain = DateTime.UtcNow;
|
||||
|
||||
var globalXp = du.TotalXp;
|
||||
var globalXp = uow.Xp.GetTotalUserXp(item.Key.User.Id);
|
||||
var oldGlobalLevelData = new LevelStats(globalXp);
|
||||
var newGlobalLevelData = new LevelStats(globalXp + xp);
|
||||
|
||||
var oldGuildLevelData = new LevelStats(usr.Xp + usr.AwardedXp);
|
||||
usr.Xp += xp;
|
||||
du.TotalXp += xp;
|
||||
if (du.Club != null)
|
||||
du.Club.Xp += xp;
|
||||
var newGuildLevelData = new LevelStats(usr.Xp + usr.AwardedXp);
|
||||
@ -308,11 +308,11 @@ namespace NadekoBot.Modules.Xp.Services
|
||||
}
|
||||
}
|
||||
|
||||
public DiscordUser[] GetUserXps(int page)
|
||||
public (ulong UserId, int TotalXp)[] GetUserXps(int page)
|
||||
{
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
return uow.DiscordUsers.GetUsersXpLeaderboardFor(page);
|
||||
return uow.Xp.GetUsersFor(page);
|
||||
}
|
||||
}
|
||||
|
||||
@ -403,6 +403,17 @@ namespace NadekoBot.Modules.Xp.Services
|
||||
return _rewardedUsers.Add(userId);
|
||||
}
|
||||
|
||||
public LevelStats GetGlobalUserStats(ulong userId)
|
||||
{
|
||||
int totalXp;
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
totalXp = uow.Xp.GetTotalUserXp(userId);
|
||||
}
|
||||
|
||||
return new LevelStats(totalXp);
|
||||
}
|
||||
|
||||
public FullUserStats GetUserStats(IGuildUser user)
|
||||
{
|
||||
DiscordUser du;
|
||||
@ -414,8 +425,8 @@ namespace NadekoBot.Modules.Xp.Services
|
||||
{
|
||||
du = uow.DiscordUsers.GetOrCreate(user);
|
||||
stats = uow.Xp.GetOrCreateUser(user.GuildId, user.Id);
|
||||
totalXp = du.TotalXp;
|
||||
globalRank = uow.DiscordUsers.GetUserGlobalRanking(user.Id);
|
||||
totalXp = uow.Xp.GetTotalUserXp(user.Id);
|
||||
globalRank = uow.Xp.GetUserGlobalRanking(user.Id);
|
||||
guildRank = uow.Xp.GetUserGuildRanking(user.Id, user.GuildId);
|
||||
}
|
||||
|
||||
@ -539,7 +550,7 @@ namespace NadekoBot.Modules.Xp.Services
|
||||
}
|
||||
}
|
||||
|
||||
public Task<MemoryStream> GenerateImageAsync(IGuildUser user)
|
||||
public Task<Image<Rgba32>> GenerateImageAsync(IGuildUser user)
|
||||
{
|
||||
return GenerateImageAsync(GetUserStats(user));
|
||||
}
|
||||
@ -555,10 +566,9 @@ namespace NadekoBot.Modules.Xp.Services
|
||||
_timeFont = _fonts.Find("Whitney-Bold").CreateFont(20);
|
||||
}
|
||||
|
||||
public Task<MemoryStream> GenerateImageAsync(FullUserStats stats) => Task.Run(async () =>
|
||||
{
|
||||
using (var img = Image.Load(_images.XpCard.ToArray()))
|
||||
public Task<Image<Rgba32>> GenerateImageAsync(FullUserStats stats) => Task.Run(async () =>
|
||||
{
|
||||
var img = Image.Load(_images.XpCard.ToArray());
|
||||
|
||||
var username = stats.User.ToString();
|
||||
var usernameFont = _usernameFontFamily
|
||||
@ -655,19 +665,20 @@ namespace NadekoBot.Modules.Xp.Services
|
||||
{
|
||||
var avatarUrl = stats.User.RealAvatarUrl();
|
||||
|
||||
var (succ, data) = await _cache.TryGetImageDataAsync(avatarUrl);
|
||||
if (!succ)
|
||||
byte[] s;
|
||||
if (!_imageStreams.TryGetValue(avatarUrl, out s))
|
||||
{
|
||||
using (var temp = await http.GetStreamAsync(avatarUrl))
|
||||
using (var tempDraw = Image.Load(temp).Resize(69, 70))
|
||||
{
|
||||
var tempDraw = Image.Load(temp);
|
||||
tempDraw = tempDraw.Resize(69, 70);
|
||||
ApplyRoundedCorners(tempDraw, 35);
|
||||
data = tempDraw.ToStream().ToArray();
|
||||
s = tempDraw.ToStream().ToArray();
|
||||
}
|
||||
|
||||
await _cache.SetImageDataAsync(avatarUrl, data);
|
||||
_imageStreams.AddOrUpdate(avatarUrl, s, (k, v) => s);
|
||||
}
|
||||
var toDraw = Image.Load(data);
|
||||
var toDraw = Image.Load(s);
|
||||
|
||||
|
||||
img.DrawImage(toDraw,
|
||||
@ -688,19 +699,20 @@ namespace NadekoBot.Modules.Xp.Services
|
||||
var imgUrl = stats.User.Club.ImageUrl;
|
||||
try
|
||||
{
|
||||
var (succ, data) = await _cache.TryGetImageDataAsync(imgUrl);
|
||||
if (!succ)
|
||||
byte[] s;
|
||||
if (!_imageStreams.TryGetValue(imgUrl, out s))
|
||||
{
|
||||
using (var temp = await http.GetStreamAsync(imgUrl))
|
||||
using (var tempDraw = Image.Load(temp).Resize(45, 45))
|
||||
{
|
||||
var tempDraw = Image.Load(temp);
|
||||
tempDraw = tempDraw.Resize(45, 45);
|
||||
ApplyRoundedCorners(tempDraw, 22.5f);
|
||||
data = tempDraw.ToStream().ToArray();
|
||||
s = tempDraw.ToStream().ToArray();
|
||||
}
|
||||
|
||||
await _cache.SetImageDataAsync(imgUrl, data);
|
||||
_imageStreams.AddOrUpdate(imgUrl, s, (k, v) => s);
|
||||
}
|
||||
var toDraw = Image.Load(data);
|
||||
var toDraw = Image.Load(s);
|
||||
|
||||
img.DrawImage(toDraw,
|
||||
1,
|
||||
@ -713,8 +725,11 @@ namespace NadekoBot.Modules.Xp.Services
|
||||
}
|
||||
}
|
||||
|
||||
return img.Resize(432, 211).ToStream();
|
||||
}
|
||||
var arr = img.ToStream().ToArray();
|
||||
|
||||
//_log.Info("{0:F2} KB", arr.Length * 1.0f / 1.KB());
|
||||
|
||||
return img;
|
||||
});
|
||||
|
||||
|
||||
|
@ -1,12 +1,10 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Discord.WebSocket;
|
||||
using NadekoBot.Common;
|
||||
using NadekoBot.Common.Attributes;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Modules.Xp.Common;
|
||||
using NadekoBot.Modules.Xp.Services;
|
||||
using NadekoBot.Services;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
@ -17,55 +15,23 @@ namespace NadekoBot.Modules.Xp
|
||||
public partial class Xp : NadekoTopLevelModule<XpService>
|
||||
{
|
||||
private readonly DiscordSocketClient _client;
|
||||
private readonly DbService _db;
|
||||
|
||||
public Xp(DiscordSocketClient client,DbService db)
|
||||
public Xp(DiscordSocketClient client)
|
||||
{
|
||||
_client = client;
|
||||
_db = db;
|
||||
}
|
||||
|
||||
//[NadekoCommand, Usage, Description, Aliases]
|
||||
//[RequireContext(ContextType.Guild)]
|
||||
//[OwnerOnly]
|
||||
//public async Task Populate()
|
||||
//{
|
||||
// var rng = new NadekoRandom();
|
||||
// using (var uow = _db.UnitOfWork)
|
||||
// {
|
||||
// for (var i = 0ul; i < 1000000; i++)
|
||||
// {
|
||||
// uow.DiscordUsers.Add(new DiscordUser()
|
||||
// {
|
||||
// AvatarId = i.ToString(),
|
||||
// Discriminator = "1234",
|
||||
// UserId = i,
|
||||
// Username = i.ToString(),
|
||||
// Club = null,
|
||||
// });
|
||||
// var xp = uow.Xp.GetOrCreateUser(Context.Guild.Id, i);
|
||||
// xp.Xp = rng.Next(100, 100000);
|
||||
// }
|
||||
// uow.Complete();
|
||||
// }
|
||||
//}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
//[Ratelimit(30)]
|
||||
public async Task Experience([Remainder]IUser user = null)
|
||||
{
|
||||
user = user ?? Context.User;
|
||||
var sw = Stopwatch.StartNew();
|
||||
|
||||
await Context.Channel.TriggerTypingAsync();
|
||||
var img = await _service.GenerateImageAsync((IGuildUser)user);
|
||||
sw.Stop();
|
||||
_log.Info("Generating finished in {0:F2}s", sw.Elapsed.TotalSeconds);
|
||||
sw.Restart();
|
||||
await Context.Channel.SendFileAsync(img, $"{user.Id}_xp.png")
|
||||
|
||||
await Context.Channel.SendFileAsync(img.ToStream(), $"{user.Id}_xp.png")
|
||||
.ConfigureAwait(false);
|
||||
sw.Stop();
|
||||
_log.Info("Sending finished in {0:F2}s", sw.Elapsed.TotalSeconds);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -74,7 +40,7 @@ namespace NadekoBot.Modules.Xp
|
||||
{
|
||||
page--;
|
||||
|
||||
if (page < 0 || page > 100)
|
||||
if (page < 0)
|
||||
return Task.CompletedTask;
|
||||
|
||||
var roles = _service.GetRoleRewards(Context.Guild.Id)
|
||||
@ -203,7 +169,7 @@ namespace NadekoBot.Modules.Xp
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public Task XpLeaderboard(int page = 1)
|
||||
{
|
||||
if (--page < 0 || page > 100)
|
||||
if (--page < 0)
|
||||
return Task.CompletedTask;
|
||||
|
||||
return Context.Channel.SendPaginatedConfirmAsync(_client, page, async (curPage) =>
|
||||
@ -244,28 +210,32 @@ namespace NadekoBot.Modules.Xp
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task XpGlobalLeaderboard(int page = 1)
|
||||
{
|
||||
if (--page < 0 || page > 100)
|
||||
if (--page < 0)
|
||||
return;
|
||||
var users = _service.GetUserXps(page);
|
||||
|
||||
await Context.Channel.SendPaginatedConfirmAsync(_client, page, async (curPage) =>
|
||||
{
|
||||
var users = _service.GetUserXps(curPage);
|
||||
|
||||
var embed = new EmbedBuilder()
|
||||
.WithTitle(GetText("global_leaderboard"))
|
||||
.WithOkColor();
|
||||
|
||||
if (!users.Any())
|
||||
embed.WithDescription("-");
|
||||
return embed.WithDescription("-");
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < users.Length; i++)
|
||||
{
|
||||
var user = users[i];
|
||||
var user = await Context.Guild.GetUserAsync(users[i].UserId).ConfigureAwait(false);
|
||||
embed.AddField(
|
||||
$"#{(i + 1 + page * 9)} {(user.ToString())}",
|
||||
$"#{(i + 1 + curPage * 9)} {(user?.ToString() ?? users[i].UserId.ToString())}",
|
||||
$"{GetText("level_x", LevelStats.FromXp(users[i].TotalXp).Level)} - {users[i].TotalXp}xp");
|
||||
}
|
||||
}
|
||||
|
||||
await Context.Channel.EmbedAsync(embed);
|
||||
return embed;
|
||||
}
|
||||
}, addPaginatedFooter: false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
|
@ -20,8 +20,6 @@ using NadekoBot.Common.ShardCom;
|
||||
using NadekoBot.Common.TypeReaders;
|
||||
using NadekoBot.Common.TypeReaders.Models;
|
||||
using NadekoBot.Services.Database;
|
||||
using StackExchange.Redis;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace NadekoBot
|
||||
{
|
||||
@ -141,7 +139,6 @@ namespace NadekoBot
|
||||
.AddManual<IEnumerable<GuildConfig>>(AllGuildConfigs) //todo wrap this
|
||||
.AddManual<NadekoBot>(this)
|
||||
.AddManual<IUnitOfWork>(uow)
|
||||
.AddManual<IDataCache>(new RedisCache())
|
||||
.LoadFrom(Assembly.GetEntryAssembly())
|
||||
.Build();
|
||||
|
||||
@ -242,6 +239,13 @@ namespace NadekoBot
|
||||
#if GLOBAL_NADEKO
|
||||
isPublicNadeko = true;
|
||||
#endif
|
||||
//_log.Info(string.Join(", ", CommandService.Commands
|
||||
// .Distinct(x => x.Name + x.Module.Name)
|
||||
// .SelectMany(x => x.Aliases)
|
||||
// .GroupBy(x => x)
|
||||
// .Where(x => x.Count() > 1)
|
||||
// .Select(x => x.Key + $"({x.Count()})")));
|
||||
|
||||
//unload modules which are not available on the public bot
|
||||
|
||||
if(isPublicNadeko)
|
||||
@ -252,7 +256,6 @@ namespace NadekoBot
|
||||
.ForEach(x => CommandService.RemoveModuleAsync(x));
|
||||
|
||||
Ready.TrySetResult(true);
|
||||
HandleStatusChanges();
|
||||
_log.Info($"Shard {Client.ShardId} ready.");
|
||||
//_log.Info(await stats.Print().ConfigureAwait(false));
|
||||
}
|
||||
@ -315,51 +318,5 @@ namespace NadekoBot
|
||||
}
|
||||
})).Start();
|
||||
}
|
||||
|
||||
private void HandleStatusChanges()
|
||||
{
|
||||
var sub = Services.GetService<IDataCache>().Redis.GetSubscriber();
|
||||
sub.Subscribe("status.game_set", async (ch, game) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var obj = new { Name = default(string) };
|
||||
obj = JsonConvert.DeserializeAnonymousType(game, obj);
|
||||
await Client.SetGameAsync(obj.Name).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.Warn(ex);
|
||||
}
|
||||
}, CommandFlags.FireAndForget);
|
||||
|
||||
sub.Subscribe("status.stream_set", async (ch, streamData) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var obj = new { Name = "", Url = "" };
|
||||
obj = JsonConvert.DeserializeAnonymousType(streamData, obj);
|
||||
await Client.SetGameAsync(obj.Name, obj.Url, StreamType.Twitch).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.Warn(ex);
|
||||
}
|
||||
}, CommandFlags.FireAndForget);
|
||||
}
|
||||
|
||||
public Task SetGameAsync(string game)
|
||||
{
|
||||
var obj = new { Name = game };
|
||||
var sub = Services.GetService<IDataCache>().Redis.GetSubscriber();
|
||||
return sub.PublishAsync("status.game_set", JsonConvert.SerializeObject(obj));
|
||||
}
|
||||
|
||||
public Task SetStreamAsync(string name, string url)
|
||||
{
|
||||
var obj = new { Name = name, Url = url };
|
||||
var sub = Services.GetService<IDataCache>().Redis.GetSubscriber();
|
||||
return sub.PublishAsync("status.game_set", JsonConvert.SerializeObject(obj));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,18 +1,30 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||
<RuntimeFrameworkVersion>2.0.0</RuntimeFrameworkVersion>
|
||||
<OutputType>exe</OutputType>
|
||||
<AssetTargetFallback>$(AssetTargetFallback);dnxcore50;portable-net45+win8+wpa81</AssetTargetFallback>
|
||||
<Description>General purpose Discord bot written in C#.</Description>
|
||||
<Copyright>Kwoth</Copyright>
|
||||
<Authors>Kwoth</Authors>
|
||||
<PublisherName>Kwoth</PublisherName>
|
||||
<TargetFramework>netcoreapp1.1</TargetFramework>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<AssemblyName>NadekoBot</AssemblyName>
|
||||
<OutputType>Exe</OutputType>
|
||||
<PackageId>NadekoBot</PackageId>
|
||||
<RuntimeFrameworkVersion>1.1.1</RuntimeFrameworkVersion>
|
||||
<PackageTargetFallback>$(PackageTargetFallback);dnxcore50;portable-net45+win8+wpa81</PackageTargetFallback>
|
||||
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
|
||||
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
|
||||
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
|
||||
<GenerateAssemblyInformationalVersionAttribute>false</GenerateAssemblyInformationalVersionAttribute>
|
||||
<GeneratePackageOnBuild>False</GeneratePackageOnBuild>
|
||||
<AssemblyVersion>1.0.0.0</AssemblyVersion>
|
||||
<FileVersion>1.0.0.0</FileVersion>
|
||||
<ApplicationIcon>nadeko_icon.ico</ApplicationIcon>
|
||||
<RuntimeIdentifiers>win7-x64<!--;ubuntu.14.04-x64;osx.10.10-x64 --></RuntimeIdentifiers>
|
||||
<Configurations>Debug;Release;global_nadeko</Configurations>
|
||||
<LangVersion>latest</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(Version)' == '' ">
|
||||
<VersionPrefix Condition=" '$(VersionPrefix)' == '' ">1.9.1</VersionPrefix>
|
||||
<VersionPrefix Condition=" '$(VersionPrefix)' == '' ">1.4.1</VersionPrefix>
|
||||
<Version Condition=" '$(VersionSuffix)' != '' ">$(VersionPrefix).$(VersionSuffix)</Version>
|
||||
<Version Condition=" '$(Version)' == '' ">$(VersionPrefix)</Version>
|
||||
</PropertyGroup>
|
||||
@ -47,24 +59,27 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AngleSharp" Version="0.9.9" />
|
||||
<PackageReference Include="Discord.Net" Version="2.0.0-alpha-build-00828" />
|
||||
<PackageReference Include="CoreCLR-NCalc" Version="2.1.3" />
|
||||
<PackageReference Include="Google.Apis.Urlshortener.v1" Version="1.29.1.138" />
|
||||
<PackageReference Include="Google.Apis.YouTube.v3" Version="1.29.1.976" />
|
||||
<PackageReference Include="Google.Apis.Customsearch.v1" Version="1.29.1.896" />
|
||||
<PackageReference Include="libvideo" Version="1.0.1" />
|
||||
<PackageReference Include="CoreCLR-NCalc" Version="2.1.2" />
|
||||
<PackageReference Include="Google.Apis.Urlshortener.v1" Version="1.19.0.138" />
|
||||
<PackageReference Include="Google.Apis.YouTube.v3" Version="1.20.0.701" />
|
||||
<PackageReference Include="Google.Apis.Customsearch.v1" Version="1.20.0.466" />
|
||||
<PackageReference Include="ImageSharp" Version="1.0.0-alpha9-00194" />
|
||||
<PackageReference Include="ImageSharp.Drawing" Version="1.0.0-alpha9-00189" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="2.0.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
|
||||
<PackageReference Include="NLog" Version="5.0.0-beta10" />
|
||||
<PackageReference Include="StackExchange.Redis" Version="1.2.6" />
|
||||
<PackageReference Include="System.ValueTuple" Version="4.4.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="1.1.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="1.1.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="1.1.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="1.1.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="1.1.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="1.1.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="1.1.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="1.1.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.PlatformAbstractions" Version="1.1.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="10.0.2" />
|
||||
<PackageReference Include="NLog" Version="5.0.0-beta03" />
|
||||
<PackageReference Include="NYoutubeDL" Version="0.4.4" />
|
||||
<PackageReference Include="System.ValueTuple" Version="4.4.0-preview1-25305-02" />
|
||||
<PackageReference Include="System.Xml.XPath" Version="4.3.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'GlobalNadeko' ">
|
||||
@ -72,12 +87,22 @@
|
||||
<NoWarn>$(NoWarn);CS1573;CS1591</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
<LangVersion>latest</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<LangVersion>latest</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.0" />
|
||||
<DotNetCliToolReference Include="Microsoft.DotNet.Watcher.Tools" Version="2.0.0" />
|
||||
<DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="1.0.0" />
|
||||
<DotNetCliToolReference Include="Microsoft.DotNet.Watcher.Tools" Version="1.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="Resources\CommandStrings.Designer.cs">
|
||||
<SubType>Designer</SubType>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
15
src/NadekoBot/NadekoBot.nuspec
Normal file
15
src/NadekoBot/NadekoBot.nuspec
Normal file
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0"?>
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>NadekoBot</id>
|
||||
<version>1.4.0-2$suffix$</version>
|
||||
<title>NadekoBot</title>
|
||||
<authors>Kwoth</authors>
|
||||
<owners>Kwoth</owners>
|
||||
<description>General purpose discord chat bot written in C#.</description>
|
||||
<tags>nadeko;bot;nadekobot;discord bot</tags>
|
||||
<projectUrl>https://github.com/Kwoth/NadekoBot</projectUrl>
|
||||
<licenseUrl>https://choosealicense.com/licenses/unlicense/</licenseUrl>
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
</metadata>
|
||||
</package>
|
7
src/NadekoBot/NadekoBot.xproj.DotSettings
Normal file
7
src/NadekoBot/NadekoBot.xproj.DotSettings
Normal file
@ -0,0 +1,7 @@
|
||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=modules_005Cadministration_005Ccommands/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=modules_005Cgambling_005Ccommands/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=modules_005Cgames_005Ccommands/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=modules_005Cpermissions_005Ccommands/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=modules_005Csearches_005Ccommands/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=modules_005Cutility_005Ccommands/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
19
src/NadekoBot/Properties/AssemblyInfo.cs
Normal file
19
src/NadekoBot/Properties/AssemblyInfo.cs
Normal file
@ -0,0 +1,19 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("NadekoBot")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyInformationalVersion("1.0")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("f8225ac4-3cbc-40b4-bcf3-1cacf276bf29")]
|
@ -3589,7 +3589,7 @@
|
||||
<value>`{0}xpex Role Excluded-Role` `{0}xpex Server`</value>
|
||||
</data>
|
||||
<data name="xpexclude_desc" xml:space="preserve">
|
||||
<value>Exclude a channel, role or current server from the xp system.</value>
|
||||
<value>Exclude a user or a role from the xp system, or whole current server.</value>
|
||||
</data>
|
||||
<data name="xpnotify_cmd" xml:space="preserve">
|
||||
<value>xpnotify xpn</value>
|
||||
@ -3780,31 +3780,4 @@
|
||||
<data name="nsfwclearcache_desc" xml:space="preserve">
|
||||
<value>Clears nsfw cache.</value>
|
||||
</data>
|
||||
<data name="clubadmin_cmd" xml:space="preserve">
|
||||
<value>clubadmin</value>
|
||||
</data>
|
||||
<data name="clubadmin_usage" xml:space="preserve">
|
||||
<value>`{0}clubadmin`</value>
|
||||
</data>
|
||||
<data name="clubadmin_desc" xml:space="preserve">
|
||||
<value>Assigns (or unassigns) staff role to the member of the club. Admins can ban, kick and accept applications.</value>
|
||||
</data>
|
||||
<data name="autoboobs_cmd" xml:space="preserve">
|
||||
<value>autoboobs</value>
|
||||
</data>
|
||||
<data name="autoboobs_desc" xml:space="preserve">
|
||||
<value>Posts a boobs every X seconds. 20 seconds minimum. Provide no arguments to disable.</value>
|
||||
</data>
|
||||
<data name="autoboobs_usage" xml:space="preserve">
|
||||
<value>`{0}autoboobs 30` or `{0}autoboobs`</value>
|
||||
</data>
|
||||
<data name="autobutts_cmd" xml:space="preserve">
|
||||
<value>autobutts</value>
|
||||
</data>
|
||||
<data name="autobutts_desc" xml:space="preserve">
|
||||
<value>Posts a butts every X seconds. 20 seconds minimum. Provide no arguments to disable.</value>
|
||||
</data>
|
||||
<data name="autobutts_usage" xml:space="preserve">
|
||||
<value>`{0}autobutts 30` or `{0}autobutts`</value>
|
||||
</data>
|
||||
</root>
|
||||
|
@ -1,5 +1,4 @@
|
||||
using Newtonsoft.Json;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace NadekoBot.Services.Database.Models
|
||||
@ -7,9 +6,7 @@ namespace NadekoBot.Services.Database.Models
|
||||
public class CustomReaction : DbEntity
|
||||
{
|
||||
public ulong? GuildId { get; set; }
|
||||
|
||||
[NotMapped]
|
||||
[JsonIgnore]
|
||||
public Regex Regex { get; set; }
|
||||
public string Response { get; set; }
|
||||
public string Trigger { get; set; }
|
||||
@ -19,7 +16,6 @@ namespace NadekoBot.Services.Database.Models
|
||||
public bool AutoDeleteTrigger { get; set; }
|
||||
public bool DmResponse { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public bool IsGlobal => !GuildId.HasValue;
|
||||
|
||||
public bool ContainsAnywhere { get; set; }
|
||||
|
@ -10,9 +10,6 @@ namespace NadekoBot.Services.Database.Models
|
||||
public string AvatarId { get; set; }
|
||||
|
||||
public ClubInfo Club { get; set; }
|
||||
public bool IsClubAdmin { get; set; }
|
||||
|
||||
public int TotalXp { get; set; }
|
||||
public DateTime LastLevelUp { get; set; } = DateTime.UtcNow;
|
||||
public DateTime LastXpGain { get; set; } = DateTime.MinValue;
|
||||
public XpNotificationType NotifyOnLevelUp { get; set; }
|
||||
|
@ -3,21 +3,23 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NadekoBot.Extensions;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Design;
|
||||
using Microsoft.Data.Sqlite;
|
||||
using System.IO;
|
||||
|
||||
namespace NadekoBot.Services.Database
|
||||
{
|
||||
public class NadekoContextFactory : IDesignTimeDbContextFactory<NadekoContext>
|
||||
|
||||
public class NadekoContextFactory : IDbContextFactory<NadekoContext>
|
||||
{
|
||||
public NadekoContext CreateDbContext(string[] args)
|
||||
/// <summary>
|
||||
/// :\ Used for migrations
|
||||
/// </summary>
|
||||
/// <param name="options"></param>
|
||||
/// <returns></returns>
|
||||
public NadekoContext Create(DbContextFactoryOptions options)
|
||||
{
|
||||
var optionsBuilder = new DbContextOptionsBuilder<NadekoContext>();
|
||||
var builder = new SqliteConnectionStringBuilder("Data Source=data/NadekoBot.db");
|
||||
builder.DataSource = Path.Combine(AppContext.BaseDirectory, builder.DataSource);
|
||||
optionsBuilder.UseSqlite(builder.ToString());
|
||||
var optionsBuilder = new DbContextOptionsBuilder();
|
||||
optionsBuilder.UseSqlite("Filename=./data/NadekoBot.db");
|
||||
var ctx = new NadekoContext(optionsBuilder.Options);
|
||||
ctx.Database.SetCommandTimeout(60);
|
||||
return ctx;
|
||||
@ -56,7 +58,12 @@ namespace NadekoBot.Services.Database
|
||||
public DbSet<ModulePrefix> ModulePrefixes { get; set; }
|
||||
public DbSet<RewardedUser> RewardedUsers { get; set; }
|
||||
|
||||
public NadekoContext(DbContextOptions<NadekoContext> options) : base(options)
|
||||
public NadekoContext() : base()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public NadekoContext(DbContextOptions options) : base(options)
|
||||
{
|
||||
}
|
||||
|
||||
@ -224,7 +231,7 @@ namespace NadekoBot.Services.Database
|
||||
musicPlaylistEntity
|
||||
.HasMany(p => p.Songs)
|
||||
.WithOne()
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
.OnDelete(Microsoft.EntityFrameworkCore.Metadata.DeleteBehavior.Cascade);
|
||||
|
||||
|
||||
#endregion
|
||||
|
@ -10,7 +10,6 @@ namespace NadekoBot.Services.Database.Repositories
|
||||
int GetNextDiscrim(string clubName);
|
||||
ClubInfo GetByName(string v, int discrim, Func<DbSet<ClubInfo>, IQueryable<ClubInfo>> func = null);
|
||||
ClubInfo GetByOwner(ulong userId, Func<DbSet<ClubInfo>, IQueryable<ClubInfo>> func = null);
|
||||
ClubInfo GetByOwnerOrAdmin(ulong userId);
|
||||
ClubInfo GetByMember(ulong userId, Func<DbSet<ClubInfo>, IQueryable<ClubInfo>> func = null);
|
||||
ClubInfo[] GetClubLeaderboardPage(int page);
|
||||
}
|
||||
|
@ -6,7 +6,5 @@ namespace NadekoBot.Services.Database.Repositories
|
||||
public interface IDiscordUserRepository : IRepository<DiscordUser>
|
||||
{
|
||||
DiscordUser GetOrCreate(IUser original);
|
||||
int GetUserGlobalRanking(ulong id);
|
||||
DiscordUser[] GetUsersXpLeaderboardFor(int page);
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,10 @@ namespace NadekoBot.Services.Database.Repositories
|
||||
public interface IXpRepository : IRepository<UserXpStats>
|
||||
{
|
||||
UserXpStats GetOrCreateUser(ulong guildId, ulong userId);
|
||||
int GetUserGuildRanking(ulong userId, ulong guildId);
|
||||
int GetTotalUserXp(ulong userId);
|
||||
UserXpStats[] GetUsersFor(ulong guildId, int page);
|
||||
(ulong UserId, int TotalXp)[] GetUsersFor(int page);
|
||||
int GetUserGlobalRanking(ulong userId);
|
||||
int GetUserGuildRanking(ulong userId, ulong guildId);
|
||||
}
|
||||
}
|
||||
|
@ -24,30 +24,6 @@ namespace NadekoBot.Services.Database.Repositories.Impl
|
||||
return func(_set).FirstOrDefault(x => x.Owner.UserId == userId);
|
||||
}
|
||||
|
||||
public ClubInfo GetByOwnerOrAdmin(ulong userId)
|
||||
{
|
||||
return _set
|
||||
.Include(x => x.Bans)
|
||||
.ThenInclude(x => x.User)
|
||||
.Include(x => x.Applicants)
|
||||
.ThenInclude(x => x.User)
|
||||
.Include(x => x.Owner)
|
||||
.FirstOrDefault(x => x.Owner.UserId == userId) ??
|
||||
_context.Set<DiscordUser>()
|
||||
.Include(x => x.Club)
|
||||
.ThenInclude(x => x.Users)
|
||||
.Include(x => x.Club)
|
||||
.ThenInclude(x => x.Bans)
|
||||
.ThenInclude(x => x.User)
|
||||
.Include(x => x.Club)
|
||||
.ThenInclude(x => x.Applicants)
|
||||
.ThenInclude(x => x.User)
|
||||
.Include(x => x.Club)
|
||||
.ThenInclude(x => x.Owner)
|
||||
.FirstOrDefault(x => x.UserId == userId && x.IsClubAdmin)
|
||||
?.Club;
|
||||
}
|
||||
|
||||
public ClubInfo GetByName(string name, int discrim, Func<DbSet<ClubInfo>, IQueryable<ClubInfo>> func = null)
|
||||
{
|
||||
if (func == null)
|
||||
|
@ -37,23 +37,5 @@ namespace NadekoBot.Services.Database.Repositories.Impl
|
||||
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
public int GetUserGlobalRanking(ulong id)
|
||||
{
|
||||
return _set.Count(x => x.TotalXp >
|
||||
_set.Where(y => y.UserId == id)
|
||||
.DefaultIfEmpty()
|
||||
.Sum(y => y.TotalXp));
|
||||
}
|
||||
|
||||
public DiscordUser[] GetUsersXpLeaderboardFor(int page)
|
||||
{
|
||||
return _set
|
||||
.OrderByDescending(x => x.TotalXp)
|
||||
.Skip(page * 9)
|
||||
.Take(9)
|
||||
.AsEnumerable()
|
||||
.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -29,6 +29,11 @@ namespace NadekoBot.Services.Database.Repositories.Impl
|
||||
return usr;
|
||||
}
|
||||
|
||||
public int GetTotalUserXp(ulong userId)
|
||||
{
|
||||
return _set.Where(x => x.UserId == userId).Sum(x => x.Xp);
|
||||
}
|
||||
|
||||
public UserXpStats[] GetUsersFor(ulong guildId, int page)
|
||||
{
|
||||
return _set.Where(x => x.GuildId == guildId)
|
||||
@ -38,6 +43,15 @@ namespace NadekoBot.Services.Database.Repositories.Impl
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
public int GetUserGlobalRanking(ulong userId)
|
||||
{
|
||||
return _set
|
||||
.GroupBy(x => x.UserId)
|
||||
.Count(x => x.Sum(y => y.Xp) > _set
|
||||
.Where(y => y.UserId == userId)
|
||||
.Sum(y => y.Xp)) + 1;
|
||||
}
|
||||
|
||||
public int GetUserGuildRanking(ulong userId, ulong guildId)
|
||||
{
|
||||
return _set
|
||||
@ -48,5 +62,16 @@ namespace NadekoBot.Services.Database.Repositories.Impl
|
||||
.DefaultIfEmpty()
|
||||
.Sum())) + 1;
|
||||
}
|
||||
|
||||
public (ulong UserId, int TotalXp)[] GetUsersFor(int page)
|
||||
{
|
||||
return _set.GroupBy(x => x.UserId)
|
||||
.OrderByDescending(x => x.Sum(y => y.Xp))
|
||||
.Skip(page * 9)
|
||||
.Take(9)
|
||||
.AsEnumerable()
|
||||
.Select(x => (x.Key, x.Sum(y => y.Xp)))
|
||||
.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,28 +1,25 @@
|
||||
using Microsoft.Data.Sqlite;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NadekoBot.Services.Database;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace NadekoBot.Services
|
||||
{
|
||||
public class DbService
|
||||
{
|
||||
private readonly DbContextOptions<NadekoContext> options;
|
||||
private readonly DbContextOptions<NadekoContext> migrateOptions;
|
||||
private readonly DbContextOptions options;
|
||||
private readonly DbContextOptions migrateOptions;
|
||||
|
||||
private readonly string _connectionString;
|
||||
|
||||
public DbService(IBotCredentials creds)
|
||||
{
|
||||
var builder = new SqliteConnectionStringBuilder(creds.Db.ConnectionString);
|
||||
builder.DataSource = Path.Combine(AppContext.BaseDirectory, builder.DataSource);
|
||||
|
||||
var optionsBuilder = new DbContextOptionsBuilder<NadekoContext>();
|
||||
optionsBuilder.UseSqlite(builder.ToString());
|
||||
_connectionString = creds.Db.ConnectionString;
|
||||
var optionsBuilder = new DbContextOptionsBuilder();
|
||||
optionsBuilder.UseSqlite(creds.Db.ConnectionString);
|
||||
options = optionsBuilder.Options;
|
||||
|
||||
optionsBuilder = new DbContextOptionsBuilder<NadekoContext>();
|
||||
optionsBuilder.UseSqlite(builder.ToString(), x => x.SuppressForeignKeyEnforcement());
|
||||
optionsBuilder = new DbContextOptionsBuilder();
|
||||
optionsBuilder.UseSqlite(creds.Db.ConnectionString, x => x.SuppressForeignKeyEnforcement());
|
||||
migrateOptions = optionsBuilder.Options;
|
||||
}
|
||||
|
||||
|
@ -1,18 +0,0 @@
|
||||
using StackExchange.Redis;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Services
|
||||
{
|
||||
public interface IDataCache
|
||||
{
|
||||
ConnectionMultiplexer Redis { get; }
|
||||
Task<(bool Success, byte[] Data)> TryGetImageDataAsync(string key);
|
||||
Task<(bool Success, string Data)> TryGetAnimeDataAsync(string key);
|
||||
Task SetImageDataAsync(string key, byte[] data);
|
||||
Task SetAnimeDataAsync(string link, string data);
|
||||
}
|
||||
}
|
@ -90,13 +90,18 @@ namespace NadekoBot.Services.Impl
|
||||
ulong.TryParse(data[nameof(ClientId)], out ulong clId);
|
||||
ClientId = clId;
|
||||
|
||||
//var scId = data[nameof(SoundCloudClientId)];
|
||||
//SoundCloudClientId = scId;
|
||||
//SoundCloudClientId = string.IsNullOrWhiteSpace(scId)
|
||||
// ?
|
||||
// : scId;
|
||||
CarbonKey = data[nameof(CarbonKey)];
|
||||
var dbSection = data.GetSection("db");
|
||||
Db = new DBConfig(string.IsNullOrWhiteSpace(dbSection["Type"])
|
||||
? "sqlite"
|
||||
: dbSection["Type"],
|
||||
string.IsNullOrWhiteSpace(dbSection["ConnectionString"])
|
||||
? "Data Source=data/NadekoBot.db"
|
||||
? "Filename=./data/NadekoBot.db"
|
||||
: dbSection["ConnectionString"]);
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -120,7 +125,7 @@ namespace NadekoBot.Services.Impl
|
||||
public string SoundCloudClientId { get; set; } = "";
|
||||
public string CleverbotApiKey { get; } = "";
|
||||
public string CarbonKey { get; set; } = "";
|
||||
public DBConfig Db { get; set; } = new DBConfig("sqlite", "Data Source=data/NadekoBot.db");
|
||||
public DBConfig Db { get; set; } = new DBConfig("sqlite", "Filename=./data/NadekoBot.db");
|
||||
public int TotalShards { get; set; } = 1;
|
||||
public string PatreonAccessToken { get; set; } = "";
|
||||
public string PatreonCampaignId { get; set; } = "334038";
|
||||
|
@ -5,9 +5,6 @@ using System.Linq;
|
||||
using Discord;
|
||||
using NLog;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NadekoBot.Common;
|
||||
using Newtonsoft.Json;
|
||||
using System.IO;
|
||||
|
||||
namespace NadekoBot.Services.Impl
|
||||
{
|
||||
@ -19,14 +16,6 @@ namespace NadekoBot.Services.Impl
|
||||
public ConcurrentDictionary<ulong, CultureInfo> GuildCultureInfos { get; }
|
||||
public CultureInfo DefaultCultureInfo { get; private set; } = CultureInfo.CurrentCulture;
|
||||
|
||||
private static readonly Dictionary<string, CommandData> _commandData;
|
||||
|
||||
static Localization()
|
||||
{
|
||||
_commandData = JsonConvert.DeserializeObject<Dictionary<string, CommandData>>(
|
||||
File.ReadAllText("./data/command_strings.json"));
|
||||
}
|
||||
|
||||
private Localization() { }
|
||||
public Localization(IBotConfigProvider bcp, IEnumerable<GuildConfig> gcs, DbService db)
|
||||
{
|
||||
@ -128,19 +117,10 @@ namespace NadekoBot.Services.Impl
|
||||
return info ?? DefaultCultureInfo;
|
||||
}
|
||||
|
||||
public static CommandData LoadCommand(string key)
|
||||
public static string LoadCommandString(string key)
|
||||
{
|
||||
_commandData.TryGetValue(key, out var toReturn);
|
||||
|
||||
if (toReturn == null)
|
||||
return new CommandData
|
||||
{
|
||||
Cmd = key,
|
||||
Desc = key,
|
||||
Usage = key,
|
||||
};
|
||||
|
||||
return toReturn;
|
||||
string toReturn = Resources.CommandStrings.ResourceManager.GetString(key);
|
||||
return string.IsNullOrWhiteSpace(toReturn) ? key : toReturn;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,40 +0,0 @@
|
||||
using StackExchange.Redis;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Services.Impl
|
||||
{
|
||||
public class RedisCache : IDataCache
|
||||
{
|
||||
public ConnectionMultiplexer Redis { get; }
|
||||
private readonly IDatabase _db;
|
||||
|
||||
public RedisCache()
|
||||
{
|
||||
Redis = ConnectionMultiplexer.Connect("127.0.0.1");
|
||||
Redis.PreserveAsyncOrder = false;
|
||||
_db = Redis.GetDatabase();
|
||||
}
|
||||
|
||||
public async Task<(bool Success, byte[] Data)> TryGetImageDataAsync(string key)
|
||||
{
|
||||
byte[] x = await _db.StringGetAsync("image_" + key);
|
||||
return (x != null, x);
|
||||
}
|
||||
|
||||
public Task SetImageDataAsync(string key, byte[] data)
|
||||
{
|
||||
return _db.StringSetAsync("image_" + key, data);
|
||||
}
|
||||
|
||||
public async Task<(bool Success, string Data)> TryGetAnimeDataAsync(string key)
|
||||
{
|
||||
string x = await _db.StringGetAsync("anime_" + key);
|
||||
return (x != null, x);
|
||||
}
|
||||
|
||||
public Task SetAnimeDataAsync(string key, string data)
|
||||
{
|
||||
return _db.StringSetAsync("anime_" + key, data);
|
||||
}
|
||||
}
|
||||
}
|
@ -20,7 +20,7 @@ namespace NadekoBot.Services.Impl
|
||||
private readonly IBotCredentials _creds;
|
||||
private readonly DateTime _started;
|
||||
|
||||
public const string BotVersion = "1.9.0";
|
||||
public const string BotVersion = "1.8.4";
|
||||
|
||||
public string Author => "Kwoth#2560";
|
||||
public string Library => "Discord.Net";
|
||||
|
@ -11,7 +11,7 @@ namespace NadekoBot.Services
|
||||
var logConfig = new LoggingConfiguration();
|
||||
var consoleTarget = new ColoredConsoleTarget()
|
||||
{
|
||||
Layout = @"${date:format=HH\:mm\:ss} ${logger:shortName=True} | ${message}"
|
||||
Layout = @"${date:format=HH\:mm\:ss} ${logger} | ${message}"
|
||||
};
|
||||
logConfig.AddTarget("Console", consoleTarget);
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
"customreactions_stats_not_found": "No stats for that trigger found, no action taken.",
|
||||
"customreactions_trigger": "Trigger",
|
||||
"customreactions_redacted_too_long": "Redecated because it's too long.",
|
||||
"nsfw_autohentai_stopped": "Autohentai stopped.",
|
||||
"nsfw_not_found": "No results found.",
|
||||
"nsfw_blacklisted_tag_list": "List of blacklisted tags:",
|
||||
"nsfw_blacklisted_tag": "One or more tags you've used are blacklisted",
|
||||
@ -867,10 +868,5 @@
|
||||
"xp_club_icon_set": "New club icon set.",
|
||||
"xp_club_bans_for": "Bans for {0} club",
|
||||
"xp_club_apps_for": "Applicants for {0} club",
|
||||
"xp_club_leaderboard": "Club leaderboard - page {0}",
|
||||
"xp_club_admin_add": "{0} is now a club admin.",
|
||||
"xp_club_admin_remove": "{0} is no longer club admin.",
|
||||
"xp_club_admin_error": "Error. You are either not the owner of the club, or that user is not in your club.",
|
||||
"nsfw_started": "Started. Reposting every {0}s.",
|
||||
"nsfw_stopped": "Stopped reposting."
|
||||
"xp_club_leaderboard": "Club leaderboard - page {0}"
|
||||
}
|
@ -13,7 +13,7 @@
|
||||
"CarbonKey": "",
|
||||
"Db": {
|
||||
"Type": "sqlite",
|
||||
"ConnectionString": "Data Source=data/NadekoBot.db"
|
||||
"ConnectionString": "Filename=./data/NadekoBot.db"
|
||||
},
|
||||
"TotalShards": 1,
|
||||
"PatreonAccessToken": "",
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user