mirror of
https://gitlab.com/Kwoth/nadekobot.git
synced 2025-09-10 17:28:27 -04:00
Compare commits
7 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
dbeb83561a | ||
|
6c11d11645 | ||
|
e9923a7691 | ||
|
5fbe93d898 | ||
|
65995bdca4 | ||
|
f7c333b671 | ||
|
f9d18aa086 |
21
CHANGELOG.md
21
CHANGELOG.md
@@ -3,6 +3,17 @@
|
||||
|
||||
Experimental changelog. Mostly based on [keepachangelog](https://keepachangelog.com/en/1.0.0/) except date format. a-c-f-r-o
|
||||
|
||||
## [4.2.2] - 15.06.2022
|
||||
|
||||
### Fixed
|
||||
|
||||
- Added missing Patron Tiers and fixed Patron pledge update bugs
|
||||
- Prevented creds_example.yml error in docker containers from crashing it
|
||||
|
||||
### Changed
|
||||
|
||||
- Rss feeds will now show error counter before deletion
|
||||
|
||||
## [4.2.1] - 14.06.2022
|
||||
|
||||
### Added
|
||||
@@ -130,6 +141,7 @@ Note: Results of each `.youtube` query will be cached for 1 hour to improve perf
|
||||
|
||||
- `.rh` no longer needs quotes for multi word roles
|
||||
- `.deletexp` will now properly delete server xp too
|
||||
- Fixed `.crypto` sparklines
|
||||
- [dev] added support for configs to properly parse enums without case sensitivity (ConfigParsers.InsensitiveEnum)
|
||||
- [dev] Fixed a bug in .gencmdlist
|
||||
- [dev] small fixes to creds provider
|
||||
@@ -139,15 +151,6 @@ Note: Results of each `.youtube` query will be cached for 1 hour to improve perf
|
||||
- `.ddg` removed.
|
||||
- [dev] removed some dead code and comments
|
||||
|
||||
### Obsolete
|
||||
|
||||
|
||||
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed `.crypto` sparklines
|
||||
|
||||
## [4.1.6] - 14.05.2022
|
||||
|
||||
### Fixed
|
||||
|
@@ -35,4 +35,14 @@ public class PatronUser
|
||||
|
||||
// Date Only component
|
||||
public DateTime ValidThru { get; set; }
|
||||
|
||||
public PatronUser Clone()
|
||||
=> new PatronUser()
|
||||
{
|
||||
UniquePlatformUserId = this.UniquePlatformUserId,
|
||||
UserId = this.UserId,
|
||||
AmountCents = this.AmountCents,
|
||||
LastCharge = this.LastCharge,
|
||||
ValidThru = this.ValidThru
|
||||
};
|
||||
}
|
@@ -75,19 +75,4 @@ public sealed class BankService : IBankService, INService
|
||||
?.Balance
|
||||
?? 0;
|
||||
}
|
||||
|
||||
public async Task<long> BurnAllAsync(ulong userId)
|
||||
{
|
||||
await using var ctx = _db.GetDbContext();
|
||||
var output = await ctx.GetTable<BankUser>()
|
||||
.Where(x => x.UserId == userId)
|
||||
.UpdateWithOutputAsync(old => new()
|
||||
{
|
||||
Balance = 0
|
||||
});
|
||||
if (output.Length == 0)
|
||||
return 0;
|
||||
|
||||
return output[0].Deleted.Balance;
|
||||
}
|
||||
}
|
@@ -5,5 +5,4 @@ public interface IBankService
|
||||
Task<bool> DepositAsync(ulong userId, long amount);
|
||||
Task<bool> WithdrawAsync(ulong userId, long amount);
|
||||
Task<long> GetBalanceAsync(ulong userId);
|
||||
Task<long> BurnAllAsync(ulong userId);
|
||||
}
|
@@ -136,7 +136,7 @@ public class ChatterBotService : IExecOnMessage
|
||||
|
||||
var channel = (ITextChannel)usrMsg.Channel;
|
||||
var conf = _ps.GetConfig();
|
||||
if (conf.IsEnabled)
|
||||
if (!_creds.IsOwner(sg.OwnerId) && conf.IsEnabled)
|
||||
{
|
||||
var quota = await _ps.TryGetFeatureLimitAsync(_flKey, sg.OwnerId, 0);
|
||||
|
||||
|
@@ -49,7 +49,7 @@ public class FeedsService : INService
|
||||
private void ClearErrors(string url)
|
||||
=> _errorCounters.Remove(url);
|
||||
|
||||
private async Task AddError(string url, List<int> ids)
|
||||
private async Task<uint> AddError(string url, List<int> ids)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -68,10 +68,13 @@ public class FeedsService : INService
|
||||
// reset the error counter
|
||||
ClearErrors(url);
|
||||
}
|
||||
|
||||
return newValue;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "Error adding rss errors...");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,12 +184,13 @@ public class FeedsService : INService
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Warning("An error occured while getting rss stream {RssFeed}"
|
||||
var errorCount = await AddError(rssUrl, kvp.Value.Select(x => x.Id).ToList());
|
||||
|
||||
Log.Warning("An error occured while getting rss stream ({ErrorCount} / 100) {RssFeed}"
|
||||
+ "\n {Message}",
|
||||
errorCount,
|
||||
rssUrl,
|
||||
$"[{ex.GetType().Name}]: {ex.Message}");
|
||||
|
||||
await AddError(rssUrl, kvp.Value.Select(x => x.Id).ToList());
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -14,5 +14,9 @@ public class PatronageConfig : ConfigServiceBase<PatronConfigData>
|
||||
|
||||
public PatronageConfig(IConfigSeria serializer, IPubSub pubSub) : base(FILE_PATH, serializer, pubSub, _changeKey)
|
||||
{
|
||||
AddParsedProp("enabled",
|
||||
x => x.IsEnabled,
|
||||
bool.TryParse,
|
||||
ConfigPrinters.ToString);
|
||||
}
|
||||
}
|
@@ -50,67 +50,91 @@ public class CurrencyRewardService : INService, IDisposable
|
||||
|
||||
private async Task OnPatronUpdate(Patron oldPatron, Patron newPatron)
|
||||
{
|
||||
if (oldPatron.Amount != newPatron.Amount)
|
||||
// if pledge was increased
|
||||
if (oldPatron.Amount < newPatron.Amount)
|
||||
{
|
||||
var conf = _config.Data;
|
||||
var newAmount = (long)(newPatron.Amount * conf.PatreonCurrencyPerCent);
|
||||
|
||||
var newAmount = (long)(Math.Max(newPatron.Amount, oldPatron.Amount) * conf.PatreonCurrencyPerCent);
|
||||
UpdateOutput<RewardedUser>[] output;
|
||||
RewardedUser old;
|
||||
await using (var ctx = _db.GetDbContext())
|
||||
{
|
||||
output = await ctx.GetTable<RewardedUser>()
|
||||
.Where(x => x.PlatformUserId == newPatron.UnqiuePlatformUserId)
|
||||
.UpdateWithOutputAsync(old => new()
|
||||
old = await ctx.GetTable<RewardedUser>()
|
||||
.Where(x => x.PlatformUserId == newPatron.UniquePlatformUserId)
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
if (old is null)
|
||||
{
|
||||
await OnNewPayment(newPatron);
|
||||
return;
|
||||
}
|
||||
|
||||
// no action as the amount is the same or lower
|
||||
if (old.AmountRewardedThisMonth >= newAmount)
|
||||
return;
|
||||
|
||||
var count = await ctx.GetTable<RewardedUser>()
|
||||
.Where(x => x.PlatformUserId == newPatron.UniquePlatformUserId)
|
||||
.UpdateAsync(_ => new()
|
||||
{
|
||||
PlatformUserId = newPatron.UnqiuePlatformUserId,
|
||||
PlatformUserId = newPatron.UniquePlatformUserId,
|
||||
UserId = newPatron.UserId,
|
||||
// amount before bonuses
|
||||
AmountRewardedThisMonth = newAmount,
|
||||
LastReward = newPatron.PaidAt
|
||||
});
|
||||
|
||||
// shouldn't ever happen
|
||||
if (count == 0)
|
||||
return;
|
||||
}
|
||||
|
||||
// if the user wasn't previously in the db for some reason,
|
||||
// we will treat him as a new patron
|
||||
if (output.Length == 0)
|
||||
{
|
||||
await OnNewPayment(newPatron);
|
||||
return;
|
||||
}
|
||||
var oldAmount = old.AmountRewardedThisMonth;
|
||||
|
||||
var oldAmount = output[0].Deleted.AmountRewardedThisMonth;
|
||||
var realNewAmount = GetRealCurrencyReward(
|
||||
(int)(newAmount / conf.PatreonCurrencyPerCent),
|
||||
newAmount,
|
||||
out var percentBonus);
|
||||
|
||||
var diff = newAmount - oldAmount;
|
||||
var realOldAmount = GetRealCurrencyReward(
|
||||
(int)(oldAmount / conf.PatreonCurrencyPerCent),
|
||||
oldAmount,
|
||||
out _);
|
||||
|
||||
var diff = realNewAmount - realOldAmount;
|
||||
if (diff <= 0)
|
||||
return; // no action if new is lower
|
||||
|
||||
// if the user pledges 5$ or more, they will get X % more flowers where X is amount in dollars,
|
||||
// up to 100%
|
||||
|
||||
var realAmount = GetRealCurrencyReward(newPatron.Amount, diff, out var percentBonus);
|
||||
await _cs.AddAsync(newPatron.UserId, realAmount, new TxData("patron","update"));
|
||||
await _cs.AddAsync(newPatron.UserId, diff, new TxData("patron","update"));
|
||||
|
||||
_ = SendMessageToUser(newPatron.UserId,
|
||||
$"You've received an additional **{realAmount}**{_config.Data.Currency.Sign} as a currency reward (+{percentBonus}%)!");
|
||||
$"You've received an additional **{diff}**{_config.Data.Currency.Sign} as a currency reward (+{percentBonus}%)!");
|
||||
}
|
||||
}
|
||||
|
||||
private long GetRealCurrencyReward(int fullPledge, long currentAmount, out int percentBonus)
|
||||
private long GetRealCurrencyReward(int pledgeCents, long modifiedAmount, out int percentBonus)
|
||||
{
|
||||
// needs at least 5$ to be eligible for a bonus
|
||||
if (fullPledge < 500)
|
||||
if (pledgeCents < 500)
|
||||
{
|
||||
percentBonus = 0;
|
||||
return currentAmount;
|
||||
return modifiedAmount;
|
||||
}
|
||||
|
||||
var dollarValue = fullPledge / 100;
|
||||
var dollarValue = pledgeCents / 100;
|
||||
percentBonus = dollarValue switch
|
||||
{
|
||||
> 100 => 100,
|
||||
_ => dollarValue
|
||||
>= 100 => 100,
|
||||
>= 50 => 50,
|
||||
>= 20 => 20,
|
||||
>= 10 => 10,
|
||||
>= 5 => 5,
|
||||
_ => 0
|
||||
};
|
||||
return (long)(currentAmount * (1 + (percentBonus / 100.0f)));
|
||||
return (long)(modifiedAmount * (1 + (percentBonus / 100.0f)));
|
||||
}
|
||||
|
||||
// on a new payment, always give the full amount.
|
||||
@@ -121,7 +145,7 @@ public class CurrencyRewardService : INService, IDisposable
|
||||
await ctx.GetTable<RewardedUser>()
|
||||
.InsertOrUpdateAsync(() => new()
|
||||
{
|
||||
PlatformUserId = patron.UnqiuePlatformUserId,
|
||||
PlatformUserId = patron.UniquePlatformUserId,
|
||||
UserId = patron.UserId,
|
||||
AmountRewardedThisMonth = amount,
|
||||
LastReward = patron.PaidAt,
|
||||
@@ -134,7 +158,7 @@ public class CurrencyRewardService : INService, IDisposable
|
||||
},
|
||||
() => new()
|
||||
{
|
||||
PlatformUserId = patron.UnqiuePlatformUserId
|
||||
PlatformUserId = patron.UniquePlatformUserId
|
||||
});
|
||||
|
||||
var realAmount = GetRealCurrencyReward(patron.Amount, amount, out var percentBonus);
|
||||
@@ -167,24 +191,9 @@ public class CurrencyRewardService : INService, IDisposable
|
||||
{
|
||||
await using var ctx = _db.GetDbContext();
|
||||
_ = await ctx.GetTable<RewardedUser>()
|
||||
.UpdateWithOutputAsync(old => new()
|
||||
.UpdateAsync(old => new()
|
||||
{
|
||||
AmountRewardedThisMonth = old.AmountRewardedThisMonth * 2
|
||||
});
|
||||
|
||||
// var toTake = old.Length == 0
|
||||
// ? patron.Amount
|
||||
// : old[0].Inserted.AmountRewardedThisMonth;
|
||||
|
||||
// if (toTake > 0)
|
||||
// {
|
||||
// Log.Warning("Wiping the wallet and bank of the user {UserId} due to a refund/fraud...",
|
||||
// patron.UserId);
|
||||
// await _cs.RemoveAsync(patron.UserId, patron.Amount, new("patreon", "refund"));
|
||||
// await _bs.BurnAllAsync(patron.UserId);
|
||||
// Log.Warning("Burned {Amount} currency from the bank of the user {UserId} due to a refund/fraud.",
|
||||
// patron.Amount,
|
||||
// patron.UserId);
|
||||
// }
|
||||
}
|
||||
}
|
@@ -5,10 +5,10 @@ public readonly struct Patron
|
||||
/// <summary>
|
||||
/// Unique id assigned to this patron by the payment platform
|
||||
/// </summary>
|
||||
public string UnqiuePlatformUserId { get; init; }
|
||||
public string UniquePlatformUserId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Discord UserId to which this <see cref="UnqiuePlatformUserId"/> is connected to
|
||||
/// Discord UserId to which this <see cref="UniquePlatformUserId"/> is connected to
|
||||
/// </summary>
|
||||
public ulong UserId { get; init; }
|
||||
|
||||
|
@@ -173,7 +173,7 @@ public sealed class PatronageService
|
||||
|
||||
var lastChargeUtc = subscriber.LastCharge.Value.ToUniversalTime();
|
||||
var dateInOneMonth = lastChargeUtc.Date.AddMonths(1);
|
||||
await using var tran = await ctx.Database.BeginTransactionAsync();
|
||||
// await using var tran = await ctx.Database.BeginTransactionAsync();
|
||||
try
|
||||
{
|
||||
var dbPatron = await ctx.GetTable<PatronUser>()
|
||||
@@ -193,7 +193,7 @@ public sealed class PatronageService
|
||||
ValidThru = dateInOneMonth,
|
||||
});
|
||||
|
||||
await tran.CommitAsync();
|
||||
// await tran.CommitAsync();
|
||||
|
||||
var newPatron = PatronUserToPatron(dbPatron);
|
||||
_ = SendWelcomeMessage(newPatron);
|
||||
@@ -222,35 +222,38 @@ public sealed class PatronageService
|
||||
// this should never happen
|
||||
if (count == 0)
|
||||
{
|
||||
await tran.RollbackAsync();
|
||||
// await tran.RollbackAsync();
|
||||
continue;
|
||||
}
|
||||
|
||||
await tran.CommitAsync();
|
||||
// await tran.CommitAsync();
|
||||
|
||||
await OnNewPatronPayment(PatronUserToPatron(dbPatron));
|
||||
}
|
||||
else if (dbPatron.AmountCents != subscriber.Cents // if user changed the amount
|
||||
|| dbPatron.UserId != subscriber.UserId) // if user updated user id)
|
||||
{
|
||||
var cents = subscriber.Cents;
|
||||
// the user updated the pledge or changed the connected discord account
|
||||
var newData = await ctx.GetTable<PatronUser>()
|
||||
.Where(x => x.UniquePlatformUserId == subscriber.UniquePlatformUserId
|
||||
&& x.LastCharge < lastChargeUtc)
|
||||
.UpdateWithOutputAsync(old => new()
|
||||
{
|
||||
UserId = subscriber.UserId,
|
||||
AmountCents = subscriber.Cents,
|
||||
LastCharge = lastChargeUtc,
|
||||
ValidThru = old.ValidThru,
|
||||
});
|
||||
await tran.CommitAsync();
|
||||
await ctx.GetTable<PatronUser>()
|
||||
.Where(x => x.UniquePlatformUserId == subscriber.UniquePlatformUserId)
|
||||
.UpdateAsync(old => new()
|
||||
{
|
||||
UserId = subscriber.UserId,
|
||||
AmountCents = cents,
|
||||
LastCharge = lastChargeUtc,
|
||||
ValidThru = old.ValidThru,
|
||||
});
|
||||
|
||||
// this should never happen
|
||||
if (newData.Length == 0)
|
||||
continue;
|
||||
var newPatron = dbPatron.Clone();
|
||||
newPatron.AmountCents = cents;
|
||||
newPatron.UserId = subscriber.UserId;
|
||||
|
||||
await OnPatronUpdated(PatronUserToPatron(dbPatron), PatronUserToPatron(newData[0].Inserted));
|
||||
// idk what's going on but UpdateWithOutputAsync doesn't work properly here
|
||||
// nor does firstordefault after update. I'm not seeing something obvious
|
||||
await OnPatronUpdated(
|
||||
PatronUserToPatron(dbPatron),
|
||||
PatronUserToPatron(newPatron));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -262,22 +265,26 @@ public sealed class PatronageService
|
||||
}
|
||||
}
|
||||
|
||||
var expiredDate = DateTime.MinValue;
|
||||
foreach (var patron in subscribers.Where(x => x.ChargeStatus == SubscriptionChargeStatus.Refunded))
|
||||
{
|
||||
var expiredDate = DateTime.MinValue;
|
||||
// if the subscription is refunded, Disable user's valid thru
|
||||
var output = await ctx.GetTable<PatronUser>()
|
||||
var changedCount = await ctx.GetTable<PatronUser>()
|
||||
.Where(x => x.UniquePlatformUserId == patron.UniquePlatformUserId
|
||||
&& x.ValidThru != expiredDate)
|
||||
.UpdateWithOutputAsync(old => new()
|
||||
.UpdateAsync(old => new()
|
||||
{
|
||||
ValidThru = expiredDate
|
||||
});
|
||||
|
||||
if (output.Length == 0)
|
||||
if (changedCount == 0)
|
||||
continue;
|
||||
|
||||
await OnPatronRefunded(PatronUserToPatron(output[0].Inserted));
|
||||
var updated = await ctx.GetTable<PatronUser>()
|
||||
.Where(x => x.UniquePlatformUserId == patron.UniquePlatformUserId)
|
||||
.FirstAsync();
|
||||
|
||||
await OnPatronRefunded(PatronUserToPatron(updated));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -641,7 +648,6 @@ public sealed class PatronageService
|
||||
};
|
||||
}
|
||||
|
||||
// should i allow users to pay extra for more quota?
|
||||
private IReadOnlyDictionary<string, FeatureQuotaStats> GetFeatureQuotaStats(
|
||||
PatronTier patronTier,
|
||||
IReadOnlyDictionary<string, PatronQuota>? allQuotasDict,
|
||||
@@ -732,7 +738,7 @@ public sealed class PatronageService
|
||||
private Patron PatronUserToPatron(PatronUser user)
|
||||
=> new Patron()
|
||||
{
|
||||
UnqiuePlatformUserId = user.UniquePlatformUserId,
|
||||
UniquePlatformUserId = user.UniquePlatformUserId,
|
||||
UserId = user.UserId,
|
||||
Amount = user.AmountCents,
|
||||
Tier = CalculateTier(user),
|
||||
@@ -747,6 +753,9 @@ public sealed class PatronageService
|
||||
|
||||
return user.AmountCents switch
|
||||
{
|
||||
>= 10_000 => PatronTier.C,
|
||||
>= 5000 => PatronTier.L,
|
||||
>= 2000 => PatronTier.XX,
|
||||
>= 1000 => PatronTier.X,
|
||||
>= 500 => PatronTier.V,
|
||||
>= 100 => PatronTier.I,
|
||||
@@ -782,7 +791,7 @@ public sealed class PatronageService
|
||||
*- Any user in any of your servers can use Patron-only commands, but they will spend **your quota**, which is why it's recommended to use Nadeko's command cooldown system (.h .cmdcd) or permission system to limit the command usage for your server members.*
|
||||
*- Permission guide can be found here if you're not familiar with it: <https://nadekobot.readthedocs.io/en/latest/permissions-system/>*",
|
||||
isInline: false)
|
||||
.WithFooter($"platform id: {patron.UnqiuePlatformUserId}");
|
||||
.WithFooter($"platform id: {patron.UniquePlatformUserId}");
|
||||
|
||||
await user.EmbedAsync(eb);
|
||||
}
|
||||
|
@@ -69,15 +69,15 @@
|
||||
<PackageReference Include="JetBrains.Annotations" Version="2022.1.0" />
|
||||
|
||||
<!-- Db-related packages -->
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.5" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.6" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.5">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
|
||||
<PackageReference Include="linq2db.EntityFrameworkCore" Version="6.7.1" />
|
||||
<PackageReference Include="linq2db.EntityFrameworkCore" Version="6.8.0" />
|
||||
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.5" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.6" />
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="6.0.4" />
|
||||
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="6.0.1" />
|
||||
|
||||
|
@@ -37,8 +37,15 @@ public sealed class BotCredsProvider : IBotCredsProvider
|
||||
public BotCredsProvider(int? totalShards = null)
|
||||
{
|
||||
_totalShards = totalShards;
|
||||
if (!File.Exists(CredsExamplePath))
|
||||
File.WriteAllText(CredsExamplePath, Yaml.Serializer.Serialize(_creds));
|
||||
try
|
||||
{
|
||||
if (!File.Exists(CredsExamplePath))
|
||||
File.WriteAllText(CredsExamplePath, Yaml.Serializer.Serialize(_creds));
|
||||
}
|
||||
catch
|
||||
{
|
||||
// this can fail in docker containers
|
||||
}
|
||||
|
||||
MigrateCredentials();
|
||||
|
||||
|
@@ -7,7 +7,7 @@ namespace NadekoBot.Services;
|
||||
|
||||
public sealed class StatsService : IStatsService, IReadyExecutor, INService
|
||||
{
|
||||
public const string BOT_VERSION = "4.2.1";
|
||||
public const string BOT_VERSION = "4.2.2";
|
||||
|
||||
public string Author
|
||||
=> "Kwoth#2452";
|
||||
|
@@ -1,66 +1,68 @@
|
||||
# DO NOT CHANGE
|
||||
version: 1
|
||||
# Whether the patronage feature is enabled
|
||||
isEnabled: false
|
||||
isEnabled: true
|
||||
# List of patron only features and relevant quota data
|
||||
quotas:
|
||||
# Dictionary of feature names with their respective limits. Set to null for unlimited
|
||||
features:
|
||||
"timely:extra_percent":
|
||||
v: 10
|
||||
x: 22
|
||||
xx: 50
|
||||
l: 150
|
||||
c: 350
|
||||
"rero:max_count":
|
||||
v: 25
|
||||
x: 50
|
||||
"cleverbot:response":
|
||||
v: -20
|
||||
x: 5000
|
||||
xx: 12000
|
||||
l: 35000
|
||||
c: 100000
|
||||
timely:extra_percent:
|
||||
V: 10
|
||||
X: 22
|
||||
XX: 50
|
||||
L: 150
|
||||
C: 350
|
||||
rero:max_count:
|
||||
V: 25
|
||||
X: 50
|
||||
cleverbot:response:
|
||||
V: -20
|
||||
X: 5000
|
||||
XX: 12000
|
||||
L: 35000
|
||||
C: 100000
|
||||
# Dictionary of commands with their respective quota data
|
||||
commands:
|
||||
cleverbot:
|
||||
V: null
|
||||
prune:
|
||||
x:
|
||||
perHour: 1
|
||||
xx:
|
||||
perHour: 3
|
||||
X:
|
||||
PerHour: 1
|
||||
XX:
|
||||
PerHour: 3
|
||||
google:
|
||||
v:
|
||||
perDay: 15
|
||||
x:
|
||||
perDay: 30
|
||||
xx:
|
||||
perDay: 60
|
||||
l:
|
||||
perDay: 150
|
||||
c:
|
||||
perDay: 300
|
||||
V:
|
||||
PerDay: 15
|
||||
X:
|
||||
PerDay: 30
|
||||
XX:
|
||||
PerDay: 60
|
||||
L:
|
||||
PerDay: 150
|
||||
C:
|
||||
PerDay: 300
|
||||
image:
|
||||
v:
|
||||
perDay: 15
|
||||
x:
|
||||
perDay: 30
|
||||
xx:
|
||||
perDay: 60
|
||||
l:
|
||||
perDay: 150
|
||||
c:
|
||||
perDay: 300
|
||||
V:
|
||||
PerDay: 15
|
||||
X:
|
||||
PerDay: 30
|
||||
XX:
|
||||
PerDay: 60
|
||||
L:
|
||||
PerDay: 150
|
||||
C:
|
||||
PerDay: 300
|
||||
youtube:
|
||||
v:
|
||||
perDay: 25
|
||||
x:
|
||||
perDay: 50
|
||||
xx:
|
||||
perDay: 100
|
||||
l:
|
||||
perDay: 250
|
||||
c:
|
||||
perDay: 500
|
||||
V:
|
||||
PerDay: 25
|
||||
X:
|
||||
PerDay: 50
|
||||
XX:
|
||||
PerDay: 100
|
||||
L:
|
||||
PerDay: 250
|
||||
C:
|
||||
PerDay: 500
|
||||
# Dictionary of groups with their respective quota data
|
||||
groups: {}
|
||||
# Dictionary of modules with their respective quota data
|
||||
|
Reference in New Issue
Block a user