Make extensive use of raw string literals C#11 feature

This commit is contained in:
Kwoth
2023-01-21 01:12:11 +01:00
parent 0fe4f14d96
commit 63a9ae2dac
32 changed files with 756 additions and 587 deletions

View File

@@ -19,19 +19,21 @@ public sealed class NadekoExpressionsService : IExecOnMessage, IReadyExecutor
private const string MENTION_PH = "%bot.mention%";
private const string PREPEND_EXPORT =
@"# Keys are triggers, Each key has a LIST of expressions in the following format:
# - res: Response string
# id: Alphanumeric id used for commands related to the expression. (Note, when using .exprsimport, a new id will be generated.)
# react:
# - <List
# - of
# - reactions>
# at: Whether expression allows targets (see .h .exprat)
# ca: Whether expression expects trigger anywhere (see .h .exprca)
# dm: Whether expression DMs the response (see .h .exprdm)
# ad: Whether expression automatically deletes triggering message (see .h .exprad)
"""
# Keys are triggers, Each key has a LIST of expressions in the following format:
# - res: Response string
# id: Alphanumeric id used for commands related to the expression. (Note, when using .exprsimport, a new id will be generated.)
# react:
# - <List
# - of
# - reactions>
# at: Whether expression allows targets (see .h .exprat)
# ca: Whether expression expects trigger anywhere (see .h .exprca)
# dm: Whether expression DMs the response (see .h .exprdm)
# ad: Whether expression automatically deletes triggering message (see .h .exprad)
";
""";
private static readonly ISerializer _exportSerializer = new SerializerBuilder()
.WithEventEmitter(args

View File

@@ -10,50 +10,58 @@ namespace NadekoBot.Modules.Gambling.Common;
[Cloneable]
public sealed partial class GamblingConfig : ICloneable<GamblingConfig>
{
[Comment(@"DO NOT CHANGE")]
[Comment("""DO NOT CHANGE""")]
public int Version { get; set; } = 2;
[Comment(@"Currency settings")]
[Comment("""Currency settings""")]
public CurrencyConfig Currency { get; set; }
[Comment(@"Minimum amount users can bet (>=0)")]
[Comment("""Minimum amount users can bet (>=0)""")]
public int MinBet { get; set; } = 0;
[Comment(@"Maximum amount users can bet
Set 0 for unlimited")]
[Comment("""
Maximum amount users can bet
Set 0 for unlimited
""")]
public int MaxBet { get; set; } = 0;
[Comment(@"Settings for betflip command")]
[Comment("""Settings for betflip command""")]
public BetFlipConfig BetFlip { get; set; }
[Comment(@"Settings for betroll command")]
[Comment("""Settings for betroll command""")]
public BetRollConfig BetRoll { get; set; }
[Comment(@"Automatic currency generation settings.")]
[Comment("""Automatic currency generation settings.""")]
public GenerationConfig Generation { get; set; }
[Comment(@"Settings for timely command
(letting people claim X amount of currency every Y hours)")]
[Comment("""
Settings for timely command
(letting people claim X amount of currency every Y hours)
""")]
public TimelyConfig Timely { get; set; }
[Comment(@"How much will each user's owned currency decay over time.")]
[Comment("""How much will each user's owned currency decay over time.""")]
public DecayConfig Decay { get; set; }
[Comment(@"Settings for LuckyLadder command")]
[Comment("""Settings for LuckyLadder command""")]
public LuckyLadderSettings LuckyLadder { get; set; }
[Comment(@"Settings related to waifus")]
[Comment("""Settings related to waifus""")]
public WaifuConfig Waifu { get; set; }
[Comment(@"Amount of currency selfhosters will get PER pledged dollar CENT.
1 = 100 currency per $. Used almost exclusively on public nadeko.")]
[Comment("""
Amount of currency selfhosters will get PER pledged dollar CENT.
1 = 100 currency per $. Used almost exclusively on public nadeko.
""")]
public decimal PatreonCurrencyPerCent { get; set; } = 1;
[Comment(@"Currency reward per vote.
This will work only if you've set up VotesApi and correct credentials for topgg and/or discords voting")]
[Comment("""
Currency reward per vote.
This will work only if you've set up VotesApi and correct credentials for topgg and/or discords voting
""")]
public long VoteReward { get; set; } = 100;
[Comment(@"Slot config")]
[Comment("""Slot config""")]
public SlotsConfig Slots { get; set; }
public GamblingConfig()
@@ -72,42 +80,50 @@ This will work only if you've set up VotesApi and correct credentials for topgg
public class CurrencyConfig
{
[Comment(@"What is the emoji/character which represents the currency")]
[Comment("""What is the emoji/character which represents the currency""")]
public string Sign { get; set; } = "🌸";
[Comment(@"What is the name of the currency")]
[Comment("""What is the name of the currency""")]
public string Name { get; set; } = "Nadeko Flower";
[Comment(@"For how long (in days) will the transactions be kept in the database (curtrs)
Set 0 to disable cleanup (keep transactions forever)")]
[Comment("""
For how long (in days) will the transactions be kept in the database (curtrs)
Set 0 to disable cleanup (keep transactions forever)
""")]
public int TransactionsLifetime { get; set; } = 0;
}
[Cloneable]
public partial class TimelyConfig
{
[Comment(@"How much currency will the users get every time they run .timely command
setting to 0 or less will disable this feature")]
[Comment("""
How much currency will the users get every time they run .timely command
setting to 0 or less will disable this feature
""")]
public int Amount { get; set; } = 0;
[Comment(@"How often (in hours) can users claim currency with .timely command
setting to 0 or less will disable this feature")]
[Comment("""
How often (in hours) can users claim currency with .timely command
setting to 0 or less will disable this feature
""")]
public int Cooldown { get; set; } = 24;
}
[Cloneable]
public partial class BetFlipConfig
{
[Comment(@"Bet multiplier if user guesses correctly")]
[Comment("""Bet multiplier if user guesses correctly""")]
public decimal Multiplier { get; set; } = 1.95M;
}
[Cloneable]
public partial class BetRollConfig
{
[Comment(@"When betroll is played, user will roll a number 0-100.
This setting will describe which multiplier is used for when the roll is higher than the given number.
Doesn't have to be ordered.")]
[Comment("""
When betroll is played, user will roll a number 0-100.
This setting will describe which multiplier is used for when the roll is higher than the given number.
Doesn't have to be ordered.
""")]
public BetRollPair[] Pairs { get; set; } = Array.Empty<BetRollPair>();
public BetRollConfig()
@@ -134,48 +150,56 @@ Doesn't have to be ordered.")]
[Cloneable]
public partial class GenerationConfig
{
[Comment(@"when currency is generated, should it also have a random password
associated with it which users have to type after the .pick command
in order to get it")]
[Comment("""
when currency is generated, should it also have a random password
associated with it which users have to type after the .pick command
in order to get it
""")]
public bool HasPassword { get; set; } = true;
[Comment(@"Every message sent has a certain % chance to generate the currency
specify the percentage here (1 being 100%, 0 being 0% - for example
default is 0.02, which is 2%")]
[Comment("""
Every message sent has a certain % chance to generate the currency
specify the percentage here (1 being 100%, 0 being 0% - for example
default is 0.02, which is 2%
""")]
public decimal Chance { get; set; } = 0.02M;
[Comment(@"How many seconds have to pass for the next message to have a chance to spawn currency")]
[Comment("""How many seconds have to pass for the next message to have a chance to spawn currency""")]
public int GenCooldown { get; set; } = 10;
[Comment(@"Minimum amount of currency that can spawn")]
[Comment("""Minimum amount of currency that can spawn""")]
public int MinAmount { get; set; } = 1;
[Comment(@"Maximum amount of currency that can spawn.
Set to the same value as MinAmount to always spawn the same amount")]
[Comment("""
Maximum amount of currency that can spawn.
Set to the same value as MinAmount to always spawn the same amount
""")]
public int MaxAmount { get; set; } = 1;
}
[Cloneable]
public partial class DecayConfig
{
[Comment(@"Percentage of user's current currency which will be deducted every 24h.
0 - 1 (1 is 100%, 0.5 50%, 0 disabled)")]
[Comment("""
Percentage of user's current currency which will be deducted every 24h.
0 - 1 (1 is 100%, 0.5 50%, 0 disabled)
""")]
public decimal Percent { get; set; } = 0;
[Comment(@"Maximum amount of user's currency that can decay at each interval. 0 for unlimited.")]
[Comment("""Maximum amount of user's currency that can decay at each interval. 0 for unlimited.""")]
public int MaxDecay { get; set; } = 0;
[Comment(@"Only users who have more than this amount will have their currency decay.")]
[Comment("""Only users who have more than this amount will have their currency decay.""")]
public int MinThreshold { get; set; } = 99;
[Comment(@"How often, in hours, does the decay run. Default is 24 hours")]
[Comment("""How often, in hours, does the decay run. Default is 24 hours""")]
public int HourInterval { get; set; } = 24;
}
[Cloneable]
public partial class LuckyLadderSettings
{
[Comment(@"Self-Explanatory. Has to have 8 values, otherwise the command won't work.")]
[Comment("""Self-Explanatory. Has to have 8 values, otherwise the command won't work.""")]
public decimal[] Multipliers { get; set; }
public LuckyLadderSettings()
@@ -185,17 +209,21 @@ public partial class LuckyLadderSettings
[Cloneable]
public sealed partial class WaifuConfig
{
[Comment(@"Minimum price a waifu can have")]
[Comment("""Minimum price a waifu can have""")]
public long MinPrice { get; set; } = 50;
public MultipliersData Multipliers { get; set; } = new();
[Comment(@"Settings for periodic waifu price decay.
Waifu price decays only if the waifu has no claimer.")]
[Comment("""
Settings for periodic waifu price decay.
Waifu price decays only if the waifu has no claimer.
""")]
public WaifuDecayConfig Decay { get; set; } = new();
[Comment(@"List of items available for gifting.
If negative is true, gift will instead reduce waifu value.")]
[Comment("""
List of items available for gifting.
If negative is true, gift will instead reduce waifu value.
""")]
public List<WaifuItemModel> Items { get; set; } = new();
public WaifuConfig()
@@ -241,16 +269,20 @@ If negative is true, gift will instead reduce waifu value.")]
public class WaifuDecayConfig
{
[Comment(@"Percentage (0 - 100) of the waifu value to reduce.
Set 0 to disable
For example if a waifu has a price of 500$, setting this value to 10 would reduce the waifu value by 10% (50$)")]
[Comment("""
Percentage (0 - 100) of the waifu value to reduce.
Set 0 to disable
For example if a waifu has a price of 500$, setting this value to 10 would reduce the waifu value by 10% (50$)
""")]
public int Percent { get; set; } = 0;
[Comment(@"How often to decay waifu values, in hours")]
[Comment("""How often to decay waifu values, in hours""")]
public int HourInterval { get; set; } = 24;
[Comment(@"Minimum waifu price required for the decay to be applied.
For example if this value is set to 300, any waifu with the price 300 or less will not experience decay.")]
[Comment("""
Minimum waifu price required for the decay to be applied.
For example if this value is set to 300, any waifu with the price 300 or less will not experience decay.
""")]
public long MinPrice { get; set; } = 300;
}
}
@@ -258,47 +290,61 @@ For example if this value is set to 300, any waifu with the price 300 or less wi
[Cloneable]
public sealed partial class MultipliersData
{
[Comment(@"Multiplier for waifureset. Default 150.
Formula (at the time of writing this):
price = (waifu_price * 1.25f) + ((number_of_divorces + changes_of_heart + 2) * WaifuReset) rounded up")]
[Comment("""
Multiplier for waifureset. Default 150.
Formula (at the time of writing this):
price = (waifu_price * 1.25f) + ((number_of_divorces + changes_of_heart + 2) * WaifuReset) rounded up
""")]
public int WaifuReset { get; set; } = 150;
[Comment(@"The minimum amount of currency that you have to pay
in order to buy a waifu who doesn't have a crush on you.
Default is 1.1
Example: If a waifu is worth 100, you will have to pay at least 100 * NormalClaim currency to claim her.
(100 * 1.1 = 110)")]
[Comment("""
The minimum amount of currency that you have to pay
in order to buy a waifu who doesn't have a crush on you.
Default is 1.1
Example: If a waifu is worth 100, you will have to pay at least 100 * NormalClaim currency to claim her.
(100 * 1.1 = 110)
""")]
public decimal NormalClaim { get; set; } = 1.1m;
[Comment(@"The minimum amount of currency that you have to pay
in order to buy a waifu that has a crush on you.
Default is 0.88
Example: If a waifu is worth 100, you will have to pay at least 100 * CrushClaim currency to claim her.
(100 * 0.88 = 88)")]
[Comment("""
The minimum amount of currency that you have to pay
in order to buy a waifu that has a crush on you.
Default is 0.88
Example: If a waifu is worth 100, you will have to pay at least 100 * CrushClaim currency to claim her.
(100 * 0.88 = 88)
""")]
public decimal CrushClaim { get; set; } = 0.88M;
[Comment(@"When divorcing a waifu, her new value will be her current value multiplied by this number.
Default 0.75 (meaning will lose 25% of her value)")]
[Comment("""
When divorcing a waifu, her new value will be her current value multiplied by this number.
Default 0.75 (meaning will lose 25% of her value)
""")]
public decimal DivorceNewValue { get; set; } = 0.75M;
[Comment(@"All gift prices will be multiplied by this number.
Default 1 (meaning no effect)")]
[Comment("""
All gift prices will be multiplied by this number.
Default 1 (meaning no effect)
""")]
public decimal AllGiftPrices { get; set; } = 1.0M;
[Comment(@"What percentage of the value of the gift will a waifu gain when she's gifted.
Default 0.95 (meaning 95%)
Example: If a waifu is worth 1000, and she receives a gift worth 100, her new value will be 1095)")]
[Comment("""
What percentage of the value of the gift will a waifu gain when she's gifted.
Default 0.95 (meaning 95%)
Example: If a waifu is worth 1000, and she receives a gift worth 100, her new value will be 1095)
""")]
public decimal GiftEffect { get; set; } = 0.95M;
[Comment(@"What percentage of the value of the gift will a waifu lose when she's gifted a gift marked as 'negative'.
Default 0.5 (meaning 50%)
Example: If a waifu is worth 1000, and she receives a negative gift worth 100, her new value will be 950)")]
[Comment("""
What percentage of the value of the gift will a waifu lose when she's gifted a gift marked as 'negative'.
Default 0.5 (meaning 50%)
Example: If a waifu is worth 1000, and she receives a negative gift worth 100, her new value will be 950)
""")]
public decimal NegativeGiftEffect { get; set; } = 0.50M;
}
public sealed class SlotsConfig
{
[Comment(@"Hex value of the color which the numbers on the slot image will have.")]
[Comment("""Hex value of the color which the numbers on the slot image will have.""")]
public Rgba32 CurrencyFontColor { get; set; } = Color.Red;
}

View File

@@ -96,9 +96,12 @@ public class GamblingService : INService, IReadyExecutor
continue;
}
Log.Information(@"Decaying users' currency - decay: {ConfigDecayPercent}%
| max: {MaxDecay}
| threshold: {DecayMinTreshold}",
Log.Information("""
--- Decaying users' currency ---
| decay: {ConfigDecayPercent}%
| max: {MaxDecay}
| threshold: {DecayMinTreshold}
""",
config.Decay.Percent * 100,
maxDecay,
config.Decay.MinThreshold);

View File

@@ -187,11 +187,13 @@ public class ChatterBotService : IExecOnMessage
// , footer: counter > 0 ? counter.ToString() : null
);
Log.Information(@"CleverBot Executed
Server: {GuildName} [{GuildId}]
Channel: {ChannelName} [{ChannelId}]
UserId: {Author} [{AuthorId}]
Message: {Content}",
Log.Information("""
CleverBot Executed
Server: {GuildName} [{GuildId}]
Channel: {ChannelName} [{ChannelId}]
UserId: {Author} [{AuthorId}]
Message: {Content}
""",
guild.Name,
guild.Id,
usrMsg.Channel?.Name,

View File

@@ -110,8 +110,10 @@ public sealed partial class TriviaConfig
[Comment("The amount of currency awarded to the winner of the trivia game.")]
public long CurrencyReward { get; set; }
[Comment(@"Users won't be able to start trivia games which have
a smaller win requirement than the one specified by this setting.")]
[Comment("""
Users won't be able to start trivia games which have
a smaller win requirement than the one specified by this setting.
""")]
public int MinimumWinReq { get; set; } = 1;
}

View File

@@ -14,13 +14,15 @@ public partial class Games
=> await SendConfirmAsync(GetText(strs.hangman_types(prefix)), _service.GetHangmanTypes().Join('\n'));
private static string Draw(HangmanGame.State state)
=> $@". ┌─────┐
.┃...............┋
.┃...............┋
.┃{(state.Errors > 0 ? ".............😲" : "")}
.{(state.Errors > 1 ? "............./" : "")} {(state.Errors > 2 ? "|" : "")} {(state.Errors > 3 ? "\\" : "")}
.{(state.Errors > 4 ? "............../" : "")} {(state.Errors > 5 ? "\\" : "")}
/-\";
=> $"""
. ┌─────┐
.┃...............┋
.┃...............┋
.┃{(state.Errors > 0 ? ".............😲" : "")}
.{(state.Errors > 1 ? "............./" : "")} {(state.Errors > 2 ? "|" : "")} {(state.Errors > 3 ? "\\" : "")}
.{(state.Errors > 4 ? "............../" : "")} {(state.Errors > 5 ? "\\" : "")}
/-\
""";
public static IEmbedBuilder GetEmbed(IEmbedBuilderService eb, HangmanGame.State state)
{

View File

@@ -69,7 +69,7 @@ public class TypingGame
try
{
await Channel.SendConfirmAsync(_eb,
$@":clock2: Next contest will last for {i} seconds. Type the bolded text as fast as you can.");
$":clock2: Next contest will last for {i} seconds. Type the bolded text as fast as you can.");
var time = _options.StartTime;

View File

@@ -78,13 +78,13 @@ public class TriviaQuestion
private static string Clean(string str)
{
str = " " + str.ToLowerInvariant() + " ";
str = Regex.Replace(str, "\\s+", " ");
str = Regex.Replace(str, "[^\\w\\d\\s]", "");
str = Regex.Replace(str, @"\s+", " ");
str = Regex.Replace(str, @"[^\w\d\s]", "");
//Here's where custom modification can be done
str = Regex.Replace(str, "\\s(a|an|the|of|in|for|to|as|at|be)\\s", " ");
str = Regex.Replace(str, @"\s(a|an|the|of|in|for|to|as|at|be)\s", " ");
//End custom mod and cleanup whitespace
str = Regex.Replace(str, "^\\s+", "");
str = Regex.Replace(str, "\\s+$", "");
str = Regex.Replace(str, @"^\s+", "");
str = Regex.Replace(str, @"\s+$", "");
//Trim the really long answers
str = str.Length <= MAX_STRING_LENGTH ? str : str[..MAX_STRING_LENGTH];
return str;

View File

@@ -490,13 +490,15 @@ public partial class Help : NadekoModule<HelpService>
private Task SelfhostAction(SocketMessageComponent smc, object _)
=> smc.RespondConfirmAsync(_eb,
@"- In case you don't want or cannot Donate to NadekoBot project, but you
- NadekoBot is a completely free and fully [open source](https://gitlab.com/kwoth/nadekobot) project which means you can run your own ""selfhosted"" instance on your computer or server for free.
*Keep in mind that running the bot on your computer means that the bot will be offline when you turn off your computer*
- You can find the selfhosting guides by using the `.guide` command and clicking on the second link that pops up.
- If you decide to selfhost the bot, still consider [supporting the project](https://patreon.com/join/nadekobot) to keep the development going :)",
"""
- In case you don't want or cannot Donate to NadekoBot project, but you
- NadekoBot is a completely free and fully [open source](https://gitlab.com/kwoth/nadekobot) project which means you can run your own "selfhosted" instance on your computer or server for free.
*Keep in mind that running the bot on your computer means that the bot will be offline when you turn off your computer*
- You can find the selfhosting guides by using the `.guide` command and clicking on the second link that pops up.
- If you decide to selfhost the bot, still consider [supporting the project](https://patreon.com/join/nadekobot) to keep the development going :)
""",
true);
[Cmd]
@@ -541,12 +543,14 @@ Nadeko will DM you the welcome instructions, and you may start using the patron-
🎉 **Enjoy!** 🎉
")
.AddField("Troubleshooting",
@"
*In case you didn't receive the rewards within 5 minutes:*
`1.` Make sure your DMs are open to everyone. Maybe your pledge was processed successfully but the bot was unable to DM you. Use the `.patron` command to check your status.
`2.` Make sure you've connected the CORRECT Discord account. Quite often users log in to different Discord accounts in their browser. You may also try disconnecting and reconnecting your account.
`3.` Make sure your payment has been processed and not declined by Patreon.
`4.` If any of the previous steps don't help, you can join the nadeko support server <https://discord.nadeko.bot> and ask for help in the #help channel");
"""
*In case you didn't receive the rewards within 5 minutes:*
`1.` Make sure your DMs are open to everyone. Maybe your pledge was processed successfully but the bot was unable to DM you. Use the `.patron` command to check your status.
`2.` Make sure you've connected the CORRECT Discord account. Quite often users log in to different Discord accounts in their browser. You may also try disconnecting and reconnecting your account.
`3.` Make sure your payment has been processed and not declined by Patreon.
`4.` If any of the previous steps don't help, you can join the nadeko support server <https://discord.nadeko.bot> and ask for help in the #help channel
""");
try
{

View File

@@ -39,9 +39,9 @@ public static class MusicExtensions
if (trackInfo.Duration == TimeSpan.MaxValue)
return "∞";
if (trackInfo.Duration.TotalHours >= 1)
return trackInfo.Duration.ToString(@"hh\:mm\:ss");
return trackInfo.Duration.ToString("""hh\:mm\:ss""");
return trackInfo.Duration.ToString(@"mm\:ss");
return trackInfo.Duration.ToString("""mm\:ss""");
}
public static ICachableTrackData ToCachedData(this ITrackInfo trackInfo, string id)

View File

@@ -5,10 +5,10 @@ namespace NadekoBot.Modules.Music.Resolvers;
public class RadioResolver : IRadioResolver
{
private readonly Regex _plsRegex = new("File1=(?<url>.*?)\\n", RegexOptions.Compiled);
private readonly Regex _m3URegex = new("(?<url>^[^#].*)", RegexOptions.Compiled | RegexOptions.Multiline);
private readonly Regex _asxRegex = new("<ref href=\"(?<url>.*?)\"", RegexOptions.Compiled);
private readonly Regex _xspfRegex = new("<location>(?<url>.*?)</location>", RegexOptions.Compiled);
private readonly Regex _plsRegex = new(@"File1=(?<url>.*?)\n", RegexOptions.Compiled);
private readonly Regex _m3URegex = new(@"(?<url>^[^#].*)", RegexOptions.Compiled | RegexOptions.Multiline);
private readonly Regex _asxRegex = new(@"<ref href=""(?<url>.*?)""", RegexOptions.Compiled);
private readonly Regex _xspfRegex = new(@"<location>(?<url>.*?)</location>", RegexOptions.Compiled);
public async Task<ITrackInfo> ResolveByQueryAsync(string query)
{

View File

@@ -24,7 +24,7 @@ public partial class Searches
var channelId = m.Groups["channelid"].Value;
return Feed("https://www.youtube.com/feeds/videos.xml?channel_id=" + channelId, channel, message);
return Feed($"https://www.youtube.com/feeds/videos.xml?channel_id={channelId}", channel, message);
}
[Cmd]

View File

@@ -304,7 +304,7 @@ public partial class Searches
private static string ShortLeagueName(string str)
{
var league = Regex.Replace(str, "Hardcore", "HC", RegexOptions.IgnoreCase);
var league = str.Replace("Hardcore", "HC", StringComparison.InvariantCultureIgnoreCase);
return league;
}

View File

@@ -9,51 +9,61 @@ public partial class SearchesConfig : ICloneable<SearchesConfig>
[Comment("DO NOT CHANGE")]
public int Version { get; set; } = 0;
[Comment(@"Which engine should .search command
'google_scrape' - default. Scrapes the webpage for results. May break. Requires no api keys.
'google' - official google api. Requires googleApiKey and google.searchId set in creds.yml
'searx' - requires at least one searx instance specified in the 'searxInstances' property below")]
[Comment("""
Which engine should .search command
'google_scrape' - default. Scrapes the webpage for results. May break. Requires no api keys.
'google' - official google api. Requires googleApiKey and google.searchId set in creds.yml
'searx' - requires at least one searx instance specified in the 'searxInstances' property below
""")]
public WebSearchEngine WebSearchEngine { get; set; } = WebSearchEngine.Google_Scrape;
[Comment(@"Which engine should .image command use
'google'- official google api. googleApiKey and google.imageSearchId set in creds.yml
'searx' requires at least one searx instance specified in the 'searxInstances' property below")]
[Comment("""
Which engine should .image command use
'google'- official google api. googleApiKey and google.imageSearchId set in creds.yml
'searx' requires at least one searx instance specified in the 'searxInstances' property below
""")]
public ImgSearchEngine ImgSearchEngine { get; set; } = ImgSearchEngine.Google;
[Comment(@"Which search provider will be used for the `.youtube` command.
- `ytDataApiv3` - uses google's official youtube data api. Requires `GoogleApiKey` set in creds and youtube data api enabled in developers console
- `ytdl` - default, uses youtube-dl. Requires `youtube-dl` to be installed and it's path added to env variables. Slow.
- `ytdlp` - recommended easy, uses `yt-dlp`. Requires `yt-dlp` to be installed and it's path added to env variables
- `invidious` - recommended advanced, uses invidious api. Requires at least one invidious instance specified in the `invidiousInstances` property")]
[Comment("""
Which search provider will be used for the `.youtube` command.
- `ytDataApiv3` - uses google's official youtube data api. Requires `GoogleApiKey` set in creds and youtube data api enabled in developers console
- `ytdl` - default, uses youtube-dl. Requires `youtube-dl` to be installed and it's path added to env variables. Slow.
- `ytdlp` - recommended easy, uses `yt-dlp`. Requires `yt-dlp` to be installed and it's path added to env variables
- `invidious` - recommended advanced, uses invidious api. Requires at least one invidious instance specified in the `invidiousInstances` property
""")]
public YoutubeSearcher YtProvider { get; set; } = YoutubeSearcher.Ytdl;
[Comment(@"Set the searx instance urls in case you want to use 'searx' for either img or web search.
Nadeko will use a random one for each request.
Use a fully qualified url. Example: `https://my-searx-instance.mydomain.com`
Instances specified must support 'format=json' query parameter.
- In case you're running your own searx instance, set
search:
formats:
- json
in 'searxng/settings.yml' on your server
- If you're using a public instance, make sure that the instance you're using supports it (they usually don't)")]
[Comment("""
Set the searx instance urls in case you want to use 'searx' for either img or web search.
Nadeko will use a random one for each request.
Use a fully qualified url. Example: `https://my-searx-instance.mydomain.com`
Instances specified must support 'format=json' query parameter.
- In case you're running your own searx instance, set
search:
formats:
- json
in 'searxng/settings.yml' on your server
- If you're using a public instance, make sure that the instance you're using supports it (they usually don't)
""")]
public List<string> SearxInstances { get; set; } = new List<string>();
[Comment(@"Set the invidious instance urls in case you want to use 'invidious' for `.youtube` search
Nadeko will use a random one for each request.
These instances may be used for music queue functionality in the future.
Use a fully qualified url. Example: https://my-invidious-instance.mydomain.com
Instances specified must have api available.
You check that by opening an api endpoint in your browser. For example: https://my-invidious-instance.mydomain.com/api/v1/trending")]
[Comment("""
Set the invidious instance urls in case you want to use 'invidious' for `.youtube` search
Nadeko will use a random one for each request.
These instances may be used for music queue functionality in the future.
Use a fully qualified url. Example: https://my-invidious-instance.mydomain.com
Instances specified must have api available.
You check that by opening an api endpoint in your browser. For example: https://my-invidious-instance.mydomain.com/api/v1/trending
""")]
public List<string> InvidiousInstances { get; set; } = new List<string>();
}

View File

@@ -23,8 +23,10 @@ public class TrovoProvider : Provider
if (string.IsNullOrWhiteSpace(creds.GetCreds().TrovoClientId))
{
Log.Warning(@"Trovo streams are using a default clientId.
If you are experiencing ratelimits, you should create your own application at: https://developer.trovo.live/");
Log.Warning("""
Trovo streams are using a default clientId.
If you are experiencing ratelimits, you should create your own application at: https://developer.trovo.live/
""");
}
}

View File

@@ -52,7 +52,7 @@ public partial class Utility
var expiryString = inv.MaxAge is null or 0 || inv.CreatedAt is null
? "∞"
: (inv.CreatedAt.Value.AddSeconds(inv.MaxAge.Value).UtcDateTime - DateTime.UtcNow).ToString(
@"d\.hh\:mm\:ss");
"""d\.hh\:mm\:ss""");
var creator = inv.Inviter.ToString().TrimTo(25);
var usesString = $"{inv.Uses} / {(inv.MaxUses == 0 ? "" : inv.MaxUses?.ToString())}";

View File

@@ -782,13 +782,15 @@ public sealed class PatronageService
patron.ValidThru.AddDays(1).ToShortAndRelativeTimestampTag(),
true)
.AddField("Instructions",
@"*- Within the next **1-2 minutes** you will have all of the benefits of the Tier you've subscribed to.*
*- You can check your benefits on <https://www.patreon.com/join/nadekobot>*
*- You can use the `.patron` command in this chat to check your current quota usage for the Patron-only commands*
*- **ALL** of the servers that you **own** will enjoy your Patron benefits.*
*- You can use any of the commands available in your tier on any server (assuming you have sufficient permissions to run those commands)*
*- 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/>*",
"""
*- Within the next **1-2 minutes** you will have all of the benefits of the Tier you've subscribed to.*
*- You can check your benefits on <https://www.patreon.com/join/nadekobot>*
*- You can use the `.patron` command in this chat to check your current quota usage for the Patron-only commands*
*- **ALL** of the servers that you **own** will enjoy your Patron benefits.*
*- You can use any of the commands available in your tier on any server (assuming you have sufficient permissions to run those commands)*
*- 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.UniquePlatformUserId}");

View File

@@ -13,12 +13,14 @@ public partial class Utility
public partial class QuoteCommands : NadekoModule
{
private const string PREPEND_EXPORT =
@"# Keys are keywords, Each key has a LIST of quotes in the following format:
# - id: Alphanumeric id used for commands related to the quote. (Note, when using .quotesimport, a new id will be generated.)
# an: Author name
# aid: Author id
# txt: Quote text
";
"""
# Keys are keywords, Each key has a LIST of quotes in the following format:
# - id: Alphanumeric id used for commands related to the quote. (Note, when using .quotesimport, a new id will be generated.)
# an: Author name
# aid: Author id
# txt: Quote text
""";
private static readonly ISerializer _exportSerializer = new SerializerBuilder()
.WithEventEmitter(args

View File

@@ -9,58 +9,68 @@ namespace NadekoBot.Modules.Xp;
[Cloneable]
public sealed partial class XpConfig : ICloneable<XpConfig>
{
[Comment(@"DO NOT CHANGE")]
[Comment("""DO NOT CHANGE""")]
public int Version { get; set; } = 5;
[Comment(@"How much XP will the users receive per message")]
[Comment("""How much XP will the users receive per message""")]
public int XpPerMessage { get; set; } = 3;
[Comment(@"How often can the users receive XP in minutes")]
[Comment("""How often can the users receive XP in minutes""")]
public int MessageXpCooldown { get; set; } = 5;
[Comment(@"Amount of xp users gain from posting an image")]
[Comment("""Amount of xp users gain from posting an image""")]
public int XpFromImage { get; set; } = 0;
[Comment(@"Average amount of xp earned per minute in VC")]
[Comment("""Average amount of xp earned per minute in VC""")]
public double VoiceXpPerMinute { get; set; } = 0;
[Comment(@"The maximum amount of minutes the bot will keep track of a user in a voice channel")]
[Comment("""The maximum amount of minutes the bot will keep track of a user in a voice channel""")]
public int VoiceMaxMinutes { get; set; } = 720;
[Comment(@"The amount of currency users will receive for each point of global xp that they earn")]
[Comment("""The amount of currency users will receive for each point of global xp that they earn""")]
public float CurrencyPerXp { get; set; } = 0;
[Comment(@"Xp Shop config")]
[Comment("""Xp Shop config""")]
public ShopConfig Shop { get; set; } = new();
public sealed class ShopConfig
{
[Comment(@"Whether the xp shop is enabled
True -> Users can access the xp shop using .xpshop command
False -> Users can't access the xp shop")]
[Comment("""
Whether the xp shop is enabled
True -> Users can access the xp shop using .xpshop command
False -> Users can't access the xp shop
""")]
public bool IsEnabled { get; set; } = false;
[Comment(@"Which patron tier do users need in order to use the .xpshop bgs command
Leave at 'None' if patron system is disabled or you don't want any restrictions")]
[Comment("""
Which patron tier do users need in order to use the .xpshop bgs command
Leave at 'None' if patron system is disabled or you don't want any restrictions
""")]
public PatronTier BgsTierRequirement { get; set; } = PatronTier.None;
[Comment(@"Which patron tier do users need in order to use the .xpshop frames command
Leave at 'None' if patron system is disabled or you don't want any restrictions")]
[Comment("""
Which patron tier do users need in order to use the .xpshop frames command
Leave at 'None' if patron system is disabled or you don't want any restrictions
""")]
public PatronTier FramesTierRequirement { get; set; } = PatronTier.None;
[Comment(@"Frames available for sale. Keys are unique IDs.
Do not change keys as they are not publicly visible. Only change properties (name, price, id)
Removing a key which previously existed means that all previous purchases will also be unusable.
To remove an item from the shop, but keep previous purchases, set the price to -1")]
[Comment("""
Frames available for sale. Keys are unique IDs.
Do not change keys as they are not publicly visible. Only change properties (name, price, id)
Removing a key which previously existed means that all previous purchases will also be unusable.
To remove an item from the shop, but keep previous purchases, set the price to -1
""")]
public Dictionary<string, ShopItemInfo>? Frames { get; set; } = new()
{
{"default", new() {Name = "No frame", Price = 0, Url = string.Empty}}
};
[Comment(@"Backgrounds available for sale. Keys are unique IDs.
Do not change keys as they are not publicly visible. Only change properties (name, price, id)
Removing a key which previously existed means that all previous purchases will also be unusable.
To remove an item from the shop, but keep previous purchases, set the price to -1")]
[Comment("""
Backgrounds available for sale. Keys are unique IDs.
Do not change keys as they are not publicly visible. Only change properties (name, price, id)
Removing a key which previously existed means that all previous purchases will also be unusable.
To remove an item from the shop, but keep previous purchases, set the price to -1
""")]
public Dictionary<string, ShopItemInfo>? Bgs { get; set; } = new()
{
{"default", new() {Name = "Default Background", Price = 0, Url = string.Empty}}
@@ -69,19 +79,19 @@ To remove an item from the shop, but keep previous purchases, set the price to -
public sealed class ShopItemInfo
{
[Comment(@"Visible name of the item")]
[Comment("""Visible name of the item""")]
public string Name { get; set; }
[Comment(@"Price of the item. Set to -1 if you no longer want to sell the item but want the users to be able to keep their old purchase")]
[Comment("""Price of the item. Set to -1 if you no longer want to sell the item but want the users to be able to keep their old purchase""")]
public int Price { get; set; }
[Comment(@"Direct url to the .png image which will be applied to the user's XP card")]
[Comment("""Direct url to the .png image which will be applied to the user's XP card""")]
public string Url { get; set; }
[Comment(@"Optional preview url which will show instead of the real URL in the shop ")]
[Comment("""Optional preview url which will show instead of the real URL in the shop """)]
public string Preview { get; set; }
[Comment(@"Optional description of the item")]
[Comment("""Optional description of the item""")]
public string Desc { get; set; }
}
}

View File

@@ -43,7 +43,7 @@ public partial class Xp
.OrderBy(x => x.Level)
.Select(x =>
{
var sign = !x.Remove ? @"✅ " : @"❌ ";
var sign = !x.Remove ? "✅ " : "❌ ";
var str = ctx.Guild.GetRole(x.RoleId)?.ToString();