diff --git a/CHANGELOG.md b/CHANGELOG.md index e97d776ef..3f353ca95 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ Experimental changelog. Mostly based on [keepachangelog](https://keepachangelog.com/en/1.0.0/) except date format. a-c-f-r-o +## [5.0.0] - ??.??.???? + +- Big internal changes + + ## [4.3.13] - 20.02.2023 ### Fixed diff --git a/Dockerfile b/Dockerfile index 65cf90f3f..fab8ff55c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build +FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build WORKDIR /source COPY src/Nadeko.Medusa/*.csproj src/Nadeko.Medusa/ diff --git a/LICENSE.md b/LICENSE.md index c99407aab..a7c27511a 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,4 +1,4 @@ -Copyright 2021 Kwoth +Copyright 2023 Kwoth Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: diff --git a/release.ps1 b/release.ps1 deleted file mode 100644 index 842eda1ab..000000000 --- a/release.ps1 +++ /dev/null @@ -1,63 +0,0 @@ -function Get-Changelog($lastTag) -{ - if(!$lastTag) - { - $lastTag = git describe --tags --abbrev=0 - } - - $tag = "$lastTag..HEAD" - - $clArr = (git log $tag --oneline) - [array]::Reverse($clArr) - $changelog = $clArr | where { "$_" -notlike "*(POEditor.com)*" -and "$_" -notlike "*Merge branch*" -and "$_" -notlike "*Merge pull request*" -and "$_" -notlike "^-*" -and "$_" -notlike "*Merge remote tracking*" } - $changelog = [string]::join([Environment]::NewLine, $changelog) - - $cl2 = $clArr | where { "$_" -like "*Merge pull request*" } - $changelog = "## Changes$nl$changelog" - if ($null -ne $cl2) { - $cl2 = [string]::join([Environment]::NewLine, $cl2) - $changelog = $changelog + "$nl ## Pull Requests Merged$nl$cl2" - } - - return $changelog -} - -function Build-Installer($versionNumber) -{ - $env:NADEKOBOT_INSTALL_VERSION = $versionNumber - - dotnet clean - # rm -r -fo "src\NadekoBot\bin" - dotnet publish -c Release --runtime win7-x64 /p:Version=$versionNumber src/NadekoBot - # .\rcedit-x64.exe "src\NadekoBot\bin\Release\netcoreapp2.1\win7-x64\nadekobot.exe" --set-icon "src\NadekoBot\bin\Release\netcoreapp2.1\win7-x64\nadeko_icon.ico" - - & "iscc.exe" "/O+" ".\exe_builder.iss" - - Write-ReleaseFile($versionNumber) - # $path = [Environment]::GetFolderPath('MyDocuments') + "\_projekti\new_installer\$versionNumber\"; - # $binPath = $path + "nadeko-setup-$versionNumber.exe"; - # Copy-Item -Path $path -Destination $dest -Force -ErrorAction Stop - - # return $path -} - -function Write-ReleaseFile($versionNumber) { - $changelog = "" - # pull the changes if they exist - # git pull - # attempt to build teh installer - # $path = Build-Installer $versionNumber - - # get changelog before tagging - $changelog = Get-Changelog - # tag the release - # & (git tag, $tag) - - # print out the changelog to the console - # Write-Host $changelog - - $jsonReleaseFile = "[{""VersionName"": ""$versionNumber"", ""DownloadLink"": ""https://cdn.nadeko.bot/dl/bot/nadeko-setup-$versionNumber.exe"", ""Changelog"": """"}]" - - $releaseJsonOutPath = [Environment]::GetFolderPath('MyDocuments') + "\_projekti\nadeko-installers\$versionNumber\" - New-Item -Path $releaseJsonOutPath -Value $jsonReleaseFile -Name "releases.json" -Force -} \ No newline at end of file diff --git a/src/Nadeko.Common/ShmartBankAmount.cs b/src/Nadeko.Common/ShmartBankAmount.cs deleted file mode 100644 index 28486026c..000000000 --- a/src/Nadeko.Common/ShmartBankAmount.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace Nadeko.Common; - -public readonly struct ShmartBankAmount -{ - public long Amount { get; } - public ShmartBankAmount(long amount) - { - Amount = amount; - } - - public static implicit operator ShmartBankAmount(long num) - => new(num); - - public static implicit operator long(ShmartBankAmount num) - => num.Amount; - - public static implicit operator ShmartBankAmount(int num) - => new(num); -} \ No newline at end of file diff --git a/src/Nadeko.Common/ShmartNumber.cs b/src/Nadeko.Common/ShmartNumber.cs deleted file mode 100644 index 1aa786318..000000000 --- a/src/Nadeko.Common/ShmartNumber.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System.Numerics; - -namespace Nadeko.Common; - -public readonly struct ShmartNumber : IEquatable -{ - public long Value { get; } - - public ShmartNumber(long val) - { - Value = val; - } - - public static implicit operator ShmartNumber(long num) - => new(num); - - public static implicit operator long(ShmartNumber num) - => num.Value; - - public static implicit operator ShmartNumber(int num) - => new(num); - - public override string ToString() - => Value.ToString(); - - public override bool Equals(object? obj) - => obj is ShmartNumber sn && Equals(sn); - - public bool Equals(ShmartNumber other) - => other.Value == Value; - - public override int GetHashCode() - => Value.GetHashCode(); - - public static bool operator ==(ShmartNumber left, ShmartNumber right) - => left.Equals(right); - - public static bool operator !=(ShmartNumber left, ShmartNumber right) - => !(left == right); -} \ No newline at end of file diff --git a/src/Nadeko.Medusa/Nadeko.Medusa.csproj b/src/Nadeko.Medusa/Nadeko.Medusa.csproj index 4b7cc9b6e..8adb79a0f 100644 --- a/src/Nadeko.Medusa/Nadeko.Medusa.csproj +++ b/src/Nadeko.Medusa/Nadeko.Medusa.csproj @@ -15,6 +15,6 @@ - 5.0.0 + 6.0.0 diff --git a/src/NadekoBot/Bot.cs b/src/NadekoBot/Bot.cs index dcd38c24a..f15216809 100644 --- a/src/NadekoBot/Bot.cs +++ b/src/NadekoBot/Bot.cs @@ -149,7 +149,7 @@ public sealed class Bot if (Client.ShardId == 0) ApplyConfigMigrations(); - _ = LoadTypeReaders(typeof(Bot).Assembly); + LoadTypeReaders(typeof(Bot).Assembly); sw.Stop(); Log.Information("All services loaded in {ServiceLoadTime:F2}s", sw.Elapsed.TotalSeconds); @@ -163,29 +163,23 @@ public sealed class Bot migrator.EnsureMigrated(); } - private IEnumerable LoadTypeReaders(Assembly assembly) + private void LoadTypeReaders(Assembly assembly) { - var allTypes = assembly.GetTypes(); - - var filteredTypes = allTypes.Where(x => x.IsSubclassOf(typeof(TypeReader)) - && x.BaseType?.GetGenericArguments().Length > 0 - && !x.IsAbstract); - - var toReturn = new List(); + var filteredTypes = assembly.GetTypes() + .Where(x => x.IsSubclassOf(typeof(TypeReader)) + && x.BaseType?.GetGenericArguments().Length > 0 + && !x.IsAbstract); + foreach (var ft in filteredTypes) { var baseType = ft.BaseType; if (baseType is null) continue; - - var x = (TypeReader)ActivatorUtilities.CreateInstance(Services, ft); - + + var typeReader = (TypeReader)ActivatorUtilities.CreateInstance(Services, ft); var typeArgs = baseType.GetGenericArguments(); - _commandService.AddTypeReader(typeArgs[0], x); - toReturn.Add(x); + _commandService.AddTypeReader(typeArgs[0], typeReader); } - - return toReturn; } private async Task LoginAsync(string token) @@ -319,7 +313,6 @@ public sealed class Bot { try { - Console.WriteLine(toExec.GetType().FullName); await toExec.OnReadyAsync(); } catch (Exception ex) diff --git a/src/NadekoBot/Common/Attributes/Aliases.cs b/src/NadekoBot/Common/Attributes/AliasesAttribute.cs similarity index 100% rename from src/NadekoBot/Common/Attributes/Aliases.cs rename to src/NadekoBot/Common/Attributes/AliasesAttribute.cs diff --git a/src/NadekoBot/Common/Attributes/NadekoCommand.cs b/src/NadekoBot/Common/Attributes/CmdAttribute.cs similarity index 100% rename from src/NadekoBot/Common/Attributes/NadekoCommand.cs rename to src/NadekoBot/Common/Attributes/CmdAttribute.cs diff --git a/src/NadekoBot/Common/Attributes/DontAddToIocContainerAttribute.cs b/src/NadekoBot/Common/Attributes/DIIgnoreAttribute.cs similarity index 78% rename from src/NadekoBot/Common/Attributes/DontAddToIocContainerAttribute.cs rename to src/NadekoBot/Common/Attributes/DIIgnoreAttribute.cs index 308681372..dcd6e6001 100644 --- a/src/NadekoBot/Common/Attributes/DontAddToIocContainerAttribute.cs +++ b/src/NadekoBot/Common/Attributes/DIIgnoreAttribute.cs @@ -5,7 +5,7 @@ namespace NadekoBot.Common; /// Classed marked with this attribute will not be added to the service provider /// [AttributeUsage(AttributeTargets.Class)] -public class DontAddToIocContainerAttribute : Attribute +public class DIIgnoreAttribute : Attribute { } \ No newline at end of file diff --git a/src/NadekoBot/Common/Attributes/NadekoOptions.cs b/src/NadekoBot/Common/Attributes/NadekoOptionsAttribute.cs similarity index 100% rename from src/NadekoBot/Common/Attributes/NadekoOptions.cs rename to src/NadekoBot/Common/Attributes/NadekoOptionsAttribute.cs diff --git a/src/NadekoBot/Common/Attributes/NoPublicBotPrecondition.cs b/src/NadekoBot/Common/Attributes/NoPublicBotAttribute.cs similarity index 56% rename from src/NadekoBot/Common/Attributes/NoPublicBotPrecondition.cs rename to src/NadekoBot/Common/Attributes/NoPublicBotAttribute.cs index 7ed29dcb9..8eca3e031 100644 --- a/src/NadekoBot/Common/Attributes/NoPublicBotPrecondition.cs +++ b/src/NadekoBot/Common/Attributes/NoPublicBotAttribute.cs @@ -18,21 +18,4 @@ public sealed class NoPublicBotAttribute : PreconditionAttribute return Task.FromResult(PreconditionResult.FromSuccess()); #endif } -} - -[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)] -[SuppressMessage("Style", "IDE0022:Use expression body for methods")] -public sealed class OnlyPublicBotAttribute : PreconditionAttribute -{ - public override Task CheckPermissionsAsync( - ICommandContext context, - CommandInfo command, - IServiceProvider services) - { -#if GLOBAL_NADEKO || DEBUG - return Task.FromResult(PreconditionResult.FromSuccess()); -#else - return Task.FromResult(PreconditionResult.FromError("Only available on the public bot.")); -#endif - } } \ No newline at end of file diff --git a/src/NadekoBot/Common/Attributes/OnlyPublicBotAttribute.cs b/src/NadekoBot/Common/Attributes/OnlyPublicBotAttribute.cs new file mode 100644 index 000000000..e9400ec17 --- /dev/null +++ b/src/NadekoBot/Common/Attributes/OnlyPublicBotAttribute.cs @@ -0,0 +1,21 @@ +#nullable disable +using System.Diagnostics.CodeAnalysis; + +namespace NadekoBot.Common; + +[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)] +[SuppressMessage("Style", "IDE0022:Use expression body for methods")] +public sealed class OnlyPublicBotAttribute : PreconditionAttribute +{ + public override Task CheckPermissionsAsync( + ICommandContext context, + CommandInfo command, + IServiceProvider services) + { +#if GLOBAL_NADEKO || DEBUG + return Task.FromResult(PreconditionResult.FromSuccess()); +#else + return Task.FromResult(PreconditionResult.FromError("Only available on the public bot.")); +#endif + } +} \ No newline at end of file diff --git a/src/NadekoBot/Common/Attributes/Ratelimit.cs b/src/NadekoBot/Common/Attributes/RatelimitAttribute.cs similarity index 100% rename from src/NadekoBot/Common/Attributes/Ratelimit.cs rename to src/NadekoBot/Common/Attributes/RatelimitAttribute.cs diff --git a/src/NadekoBot/Common/Attributes/UserPerm.cs b/src/NadekoBot/Common/Attributes/UserPermAttribute.cs similarity index 100% rename from src/NadekoBot/Common/Attributes/UserPerm.cs rename to src/NadekoBot/Common/Attributes/UserPermAttribute.cs diff --git a/src/NadekoBot/Common/Attributes/CommandNameLoadHelper.cs b/src/NadekoBot/Common/CommandNameLoadHelper.cs similarity index 100% rename from src/NadekoBot/Common/Attributes/CommandNameLoadHelper.cs rename to src/NadekoBot/Common/CommandNameLoadHelper.cs diff --git a/src/NadekoBot/Common/Medusa/Adapters/BehaviorAdapter.cs b/src/NadekoBot/Common/Medusa/Adapters/BehaviorAdapter.cs index ea0c06da7..2e369824a 100644 --- a/src/NadekoBot/Common/Medusa/Adapters/BehaviorAdapter.cs +++ b/src/NadekoBot/Common/Medusa/Adapters/BehaviorAdapter.cs @@ -1,6 +1,6 @@ #nullable enable -[DontAddToIocContainer] +[DIIgnore] public sealed class BehaviorAdapter : ICustomBehavior { private readonly WeakReference _snekWr; diff --git a/src/NadekoBot/Common/TypeReaders/Shmart/ShmartBankAmountTypeReader.cs b/src/NadekoBot/Common/TypeReaders/Shmart/ShmartBankAmountTypeReader.cs deleted file mode 100644 index 8dc93f525..000000000 --- a/src/NadekoBot/Common/TypeReaders/Shmart/ShmartBankAmountTypeReader.cs +++ /dev/null @@ -1,32 +0,0 @@ -#nullable disable -using NadekoBot.Modules.Gambling.Bank; -using NadekoBot.Modules.Gambling.Services; - -namespace NadekoBot.Common.TypeReaders; - -public sealed class ShmartBankAmountTypeReader : NadekoTypeReader -{ - private readonly IBankService _bank; - private readonly ShmartBankInputAmountReader _tr; - - public ShmartBankAmountTypeReader(IBankService bank, DbService db, GamblingConfigService gambling) - { - _bank = bank; - _tr = new ShmartBankInputAmountReader(bank, db, gambling); - } - - public override async ValueTask> ReadAsync(ICommandContext ctx, string input) - { - if (string.IsNullOrWhiteSpace(input)) - return TypeReaderResult.FromError(CommandError.ParseFailed, "Input is empty."); - - var result = await _tr.ReadAsync(ctx, input); - - if (result.TryPickT0(out var val, out var err)) - { - return TypeReaderResult.FromSuccess(new(val)); - } - - return TypeReaderResult.FromError(CommandError.Unsuccessful, err.Value); - } -} \ No newline at end of file diff --git a/src/NadekoBot/Common/TypeReaders/Shmart/ShmartNumberTypeReader.cs b/src/NadekoBot/Common/TypeReaders/Shmart/ShmartNumberTypeReader.cs index ea98dd6f8..09c992db9 100644 --- a/src/NadekoBot/Common/TypeReaders/Shmart/ShmartNumberTypeReader.cs +++ b/src/NadekoBot/Common/TypeReaders/Shmart/ShmartNumberTypeReader.cs @@ -1,29 +1,57 @@ #nullable disable +using NadekoBot.Modules.Gambling.Bank; using NadekoBot.Modules.Gambling.Services; namespace NadekoBot.Common.TypeReaders; -public sealed class ShmartNumberTypeReader : NadekoTypeReader +public sealed class BalanceTypeReader : TypeReader { private readonly BaseShmartInputAmountReader _tr; - public ShmartNumberTypeReader(DbService db, GamblingConfigService gambling) + public BalanceTypeReader(DbService db, GamblingConfigService gambling) { - _tr = new BaseShmartInputAmountReader(db, gambling); + _tr = new BaseShmartInputAmountReader(db, gambling); } - - public override async ValueTask> ReadAsync(ICommandContext ctx, string input) + + public override async Task ReadAsync( + ICommandContext context, + string input, + IServiceProvider services) { - if (string.IsNullOrWhiteSpace(input)) - return TypeReaderResult.FromError(CommandError.ParseFailed, "Input is empty."); - var result = await _tr.ReadAsync(ctx, input); + var result = await _tr.ReadAsync(context, input); if (result.TryPickT0(out var val, out var err)) { - return TypeReaderResult.FromSuccess(new(val)); + return Discord.Commands.TypeReaderResult.FromSuccess(val); } + + return Discord.Commands.TypeReaderResult.FromError(CommandError.Unsuccessful, err.Value); + } +} - return TypeReaderResult.FromError(CommandError.Unsuccessful, err.Value); +public sealed class BankBalanceTypeReader : TypeReader +{ + private readonly ShmartBankInputAmountReader _tr; + + public BankBalanceTypeReader(IBankService bank, DbService db, GamblingConfigService gambling) + { + _tr = new ShmartBankInputAmountReader(bank, db, gambling); + } + + public override async Task ReadAsync( + ICommandContext context, + string input, + IServiceProvider services) + { + + var result = await _tr.ReadAsync(context, input); + + if (result.TryPickT0(out var val, out var err)) + { + return Discord.Commands.TypeReaderResult.FromSuccess(val); + } + + return Discord.Commands.TypeReaderResult.FromError(CommandError.Unsuccessful, err.Value); } } \ No newline at end of file diff --git a/src/NadekoBot/Modules/Gambling/AnimalRacing/AnimalRacingCommands.cs b/src/NadekoBot/Modules/Gambling/AnimalRacing/AnimalRacingCommands.cs index 28f5e929e..19d0b4c32 100644 --- a/src/NadekoBot/Modules/Gambling/AnimalRacing/AnimalRacingCommands.cs +++ b/src/NadekoBot/Modules/Gambling/AnimalRacing/AnimalRacingCommands.cs @@ -1,5 +1,6 @@ #nullable disable using Nadeko.Common; +using NadekoBot.Common.TypeReaders; using NadekoBot.Modules.Gambling.Common; using NadekoBot.Modules.Gambling.Common.AnimalRacing; using NadekoBot.Modules.Gambling.Common.AnimalRacing.Exceptions; @@ -135,7 +136,7 @@ public partial class Gambling [Cmd] [RequireContext(ContextType.Guild)] - public async Task JoinRace(ShmartNumber amount = default) + public async Task JoinRace([OverrideTypeReader(typeof(BalanceTypeReader))] long amount = default) { if (!await CheckBetOptional(amount)) return; diff --git a/src/NadekoBot/Modules/Gambling/Bank/BankCommands.cs b/src/NadekoBot/Modules/Gambling/Bank/BankCommands.cs index c96019950..e2899149a 100644 --- a/src/NadekoBot/Modules/Gambling/Bank/BankCommands.cs +++ b/src/NadekoBot/Modules/Gambling/Bank/BankCommands.cs @@ -1,4 +1,5 @@ -using NadekoBot.Modules.Gambling.Bank; +using NadekoBot.Common.TypeReaders; +using NadekoBot.Modules.Gambling.Bank; using NadekoBot.Modules.Gambling.Common; using NadekoBot.Modules.Gambling.Services; @@ -22,14 +23,14 @@ public partial class Gambling } [Cmd] - public async Task BankDeposit(ShmartNumber amount) + public async Task BankDeposit([OverrideTypeReader(typeof(BalanceTypeReader))] long amount) { if (amount <= 0) return; if (await _bank.DepositAsync(ctx.User.Id, amount)) { - await ReplyConfirmLocalizedAsync(strs.bank_deposited(N(amount.Value))); + await ReplyConfirmLocalizedAsync(strs.bank_deposited(N(amount))); } else { @@ -38,14 +39,14 @@ public partial class Gambling } [Cmd] - public async Task BankWithdraw(ShmartBankAmount amount) + public async Task BankWithdraw([OverrideTypeReader(typeof(BankBalanceTypeReader))] long amount) { if (amount <= 0) return; if (await _bank.WithdrawAsync(ctx.User.Id, amount)) { - await ReplyConfirmLocalizedAsync(strs.bank_withdrew(N(amount.Amount))); + await ReplyConfirmLocalizedAsync(strs.bank_withdrew(N(amount))); } else { diff --git a/src/NadekoBot/Modules/Gambling/BlackJack/BlackJackCommands.cs b/src/NadekoBot/Modules/Gambling/BlackJack/BlackJackCommands.cs index f71acdb62..4979256c7 100644 --- a/src/NadekoBot/Modules/Gambling/BlackJack/BlackJackCommands.cs +++ b/src/NadekoBot/Modules/Gambling/BlackJack/BlackJackCommands.cs @@ -1,5 +1,6 @@ #nullable disable using Nadeko.Common; +using NadekoBot.Common.TypeReaders; using NadekoBot.Modules.Gambling.Common; using NadekoBot.Modules.Gambling.Common.Blackjack; using NadekoBot.Modules.Gambling.Services; @@ -30,7 +31,7 @@ public partial class Gambling [Cmd] [RequireContext(ContextType.Guild)] - public async Task BlackJack(ShmartNumber amount) + public async Task BlackJack([OverrideTypeReader(typeof(BalanceTypeReader))] long amount) { if (!await CheckBetMandatory(amount)) return; diff --git a/src/NadekoBot/Modules/Gambling/Draw/DrawCommands.cs b/src/NadekoBot/Modules/Gambling/Draw/DrawCommands.cs index 72ae5b4ec..d83d0263b 100644 --- a/src/NadekoBot/Modules/Gambling/Draw/DrawCommands.cs +++ b/src/NadekoBot/Modules/Gambling/Draw/DrawCommands.cs @@ -1,5 +1,6 @@ #nullable disable using Nadeko.Econ; +using NadekoBot.Common.TypeReaders; using NadekoBot.Modules.Gambling.Common; using NadekoBot.Modules.Gambling.Services; using SixLabors.ImageSharp; @@ -135,12 +136,12 @@ public partial class Gambling [Cmd] [RequireContext(ContextType.Guild)] - public Task BetDraw(ShmartNumber amount, InputValueGuess val, InputColorGuess? col = null) + public Task BetDraw([OverrideTypeReader(typeof(BalanceTypeReader))] long amount, InputValueGuess val, InputColorGuess? col = null) => BetDrawInternal(amount, val, col); [Cmd] [RequireContext(ContextType.Guild)] - public Task BetDraw(ShmartNumber amount, InputColorGuess col, InputValueGuess? val = null) + public Task BetDraw([OverrideTypeReader(typeof(BalanceTypeReader))] long amount, InputColorGuess col, InputValueGuess? val = null) => BetDrawInternal(amount, val, col); public async Task BetDrawInternal(long amount, InputValueGuess? val, InputColorGuess? col) diff --git a/src/NadekoBot/Modules/Gambling/FlipCoin/FlipCoinCommands.cs b/src/NadekoBot/Modules/Gambling/FlipCoin/FlipCoinCommands.cs index c4347fbe9..a12dd29b8 100644 --- a/src/NadekoBot/Modules/Gambling/FlipCoin/FlipCoinCommands.cs +++ b/src/NadekoBot/Modules/Gambling/FlipCoin/FlipCoinCommands.cs @@ -1,5 +1,6 @@ #nullable disable using Nadeko.Common; +using NadekoBot.Common.TypeReaders; using NadekoBot.Modules.Gambling.Common; using NadekoBot.Modules.Gambling.Services; using SixLabors.ImageSharp; @@ -96,7 +97,7 @@ public partial class Gambling } [Cmd] - public async Task Betflip(ShmartNumber amount, BetFlipGuess guess) + public async Task Betflip([OverrideTypeReader(typeof(BalanceTypeReader))] long amount, BetFlipGuess guess) { if (!await CheckBetMandatory(amount) || amount == 1) return; diff --git a/src/NadekoBot/Modules/Gambling/Gambling.cs b/src/NadekoBot/Modules/Gambling/Gambling.cs index c64cc4411..28bd148b8 100644 --- a/src/NadekoBot/Modules/Gambling/Gambling.cs +++ b/src/NadekoBot/Modules/Gambling/Gambling.cs @@ -14,6 +14,7 @@ using System.Collections.Immutable; using System.Globalization; using System.Text; using Nadeko.Econ.Gambling.Rps; +using NadekoBot.Common.TypeReaders; namespace NadekoBot.Modules.Gambling; @@ -428,26 +429,26 @@ public partial class Gambling : GamblingModule [Cmd] [RequireContext(ContextType.Guild)] [Priority(0)] - public async Task Give(ShmartNumber amount, IGuildUser receiver, [Leftover] string msg) + public async Task Give([OverrideTypeReader(typeof(BalanceTypeReader))] long amount, IGuildUser receiver, [Leftover] string msg) { if (amount <= 0 || ctx.User.Id == receiver.Id || receiver.IsBot) { return; } - if (!await _cs.TransferAsync(_eb, ctx.User, receiver, amount, msg, N(amount.Value))) + if (!await _cs.TransferAsync(_eb, ctx.User, receiver, amount, msg, N(amount))) { await ReplyErrorLocalizedAsync(strs.not_enough(CurrencySign)); return; } - await ReplyConfirmLocalizedAsync(strs.gifted(N(amount.Value), Format.Bold(receiver.ToString()))); + await ReplyConfirmLocalizedAsync(strs.gifted(N(amount), Format.Bold(receiver.ToString()))); } [Cmd] [RequireContext(ContextType.Guild)] [Priority(1)] - public Task Give(ShmartNumber amount, [Leftover] IGuildUser receiver) + public Task Give([OverrideTypeReader(typeof(BalanceTypeReader))] long amount, [Leftover] IGuildUser receiver) => Give(amount, receiver, null); [Cmd] @@ -583,7 +584,7 @@ public partial class Gambling : GamblingModule [Cmd] [RequireContext(ContextType.Guild)] - public async Task RollDuel(ShmartNumber amount, IUser u) + public async Task RollDuel([OverrideTypeReader(typeof(BalanceTypeReader))] long amount, IUser u) { if (ctx.User.Id == u.Id) { @@ -622,7 +623,7 @@ public partial class Gambling : GamblingModule await ReplyConfirmLocalizedAsync(strs.roll_duel_challenge(Format.Bold(ctx.User.ToString()), Format.Bold(u.ToString()), - Format.Bold(N(amount.Value)))); + Format.Bold(N(amount)))); } async Task GameOnGameTick(RollDuelGame arg) @@ -674,7 +675,7 @@ public partial class Gambling : GamblingModule } [Cmd] - public async Task BetRoll(ShmartNumber amount) + public async Task BetRoll([OverrideTypeReader(typeof(BalanceTypeReader))] long amount) { if (!await CheckBetMandatory(amount)) { @@ -804,7 +805,7 @@ public partial class Gambling : GamblingModule } [Cmd] - public async Task Rps(InputRpsPick pick, ShmartNumber amount = default) + public async Task Rps(InputRpsPick pick, [OverrideTypeReader(typeof(BalanceTypeReader))] long amount = default) { static string GetRpsPick(InputRpsPick p) { @@ -840,7 +841,7 @@ public partial class Gambling : GamblingModule else if (result.Result == RpsResultType.Win) { if ((long)result.Won > 0) - embed.AddField(GetText(strs.won), N(amount.Value)); + embed.AddField(GetText(strs.won), N(amount)); msg = GetText(strs.rps_win(ctx.User.Mention, GetRpsPick(pick), @@ -864,7 +865,7 @@ public partial class Gambling : GamblingModule new[] { "⬆", "↖", "⬅", "↙", "⬇", "↘", "➡", "↗" }.ToImmutableArray(); [Cmd] - public async Task LuckyLadder(ShmartNumber amount) + public async Task LuckyLadder([OverrideTypeReader(typeof(BalanceTypeReader))] long amount) { if (!await CheckBetMandatory(amount)) return; diff --git a/src/NadekoBot/Modules/Gambling/PlantPick/PlantAndPickCommands.cs b/src/NadekoBot/Modules/Gambling/PlantPick/PlantAndPickCommands.cs index ecc5f6dd7..a76a12fa4 100644 --- a/src/NadekoBot/Modules/Gambling/PlantPick/PlantAndPickCommands.cs +++ b/src/NadekoBot/Modules/Gambling/PlantPick/PlantAndPickCommands.cs @@ -1,5 +1,6 @@ #nullable disable using Nadeko.Common; +using NadekoBot.Common.TypeReaders; using NadekoBot.Modules.Gambling.Common; using NadekoBot.Modules.Gambling.Services; @@ -44,7 +45,7 @@ public partial class Gambling [Cmd] [RequireContext(ContextType.Guild)] - public async Task Plant(ShmartNumber amount, string pass = null) + public async Task Plant([OverrideTypeReader(typeof(BalanceTypeReader))] long amount, string pass = null) { if (amount < 1) return; diff --git a/src/NadekoBot/Modules/Gambling/Raffle/CurrencyRaffleCommands.cs b/src/NadekoBot/Modules/Gambling/Raffle/CurrencyRaffleCommands.cs index 223e80650..675954a90 100644 --- a/src/NadekoBot/Modules/Gambling/Raffle/CurrencyRaffleCommands.cs +++ b/src/NadekoBot/Modules/Gambling/Raffle/CurrencyRaffleCommands.cs @@ -1,5 +1,6 @@ #nullable disable using Nadeko.Common; +using NadekoBot.Common.TypeReaders; using NadekoBot.Modules.Gambling.Common; using NadekoBot.Modules.Gambling.Services; @@ -19,13 +20,13 @@ public partial class Gambling [Cmd] [RequireContext(ContextType.Guild)] [Priority(0)] - public Task RaffleCur(Mixed _, ShmartNumber amount) + public Task RaffleCur(Mixed _, [OverrideTypeReader(typeof(BalanceTypeReader))] long amount) => RaffleCur(amount, true); [Cmd] [RequireContext(ContextType.Guild)] [Priority(1)] - public async Task RaffleCur(ShmartNumber amount, bool mixed = false) + public async Task RaffleCur([OverrideTypeReader(typeof(BalanceTypeReader))] long amount, bool mixed = false) { if (!await CheckBetMandatory(amount)) return; diff --git a/src/NadekoBot/Modules/Gambling/Slot/SlotCommands.cs b/src/NadekoBot/Modules/Gambling/Slot/SlotCommands.cs index 4bd9473ec..f0a6db472 100644 --- a/src/NadekoBot/Modules/Gambling/Slot/SlotCommands.cs +++ b/src/NadekoBot/Modules/Gambling/Slot/SlotCommands.cs @@ -9,6 +9,7 @@ using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; using System.Text; using Nadeko.Econ.Gambling; +using NadekoBot.Common.TypeReaders; using Color = SixLabors.ImageSharp.Color; using Image = SixLabors.ImageSharp.Image; @@ -48,7 +49,7 @@ public partial class Gambling => Task.CompletedTask; [Cmd] - public async Task Slot(ShmartNumber amount) + public async Task Slot([OverrideTypeReader(typeof(BalanceTypeReader))] long amount) { if (!await CheckBetMandatory(amount)) return; @@ -76,7 +77,7 @@ public partial class Gambling .WithOkColor(); var bb = new ButtonBuilder(emote: Emoji.Parse("🔁"), customId: "slot:again", label: "Pull Again"); - var si = new SimpleInteraction(bb, (_, amount) => Slot(amount), amount); + var si = new SimpleInteraction(bb, (_, amount) => Slot(amount), amount); var inter = _inter.Create(ctx.User.Id, si); var msg = await ctx.Channel.SendFileAsync(imgStream, diff --git a/src/NadekoBot/Modules/Medusae/IMedusaeRepositoryService.cs b/src/NadekoBot/Modules/Medusae/IMedusaeRepositoryService.cs new file mode 100644 index 000000000..769491181 --- /dev/null +++ b/src/NadekoBot/Modules/Medusae/IMedusaeRepositoryService.cs @@ -0,0 +1,6 @@ +namespace NadekoBot.Modules; + +public interface IMedusaeRepositoryService +{ + Task> GetModuleItemsAsync(); +} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Medusae/Medusa.cs b/src/NadekoBot/Modules/Medusae/Medusa.cs index 13ba3d2f1..f1897c294 100644 --- a/src/NadekoBot/Modules/Medusae/Medusa.cs +++ b/src/NadekoBot/Modules/Medusae/Medusa.cs @@ -6,6 +6,13 @@ namespace NadekoBot.Modules; [OwnerOnly] public partial class Medusa : NadekoModule { + private readonly IMedusaeRepositoryService _repo; + + public Medusa(IMedusaeRepositoryService repo) + { + _repo = repo; + } + [Cmd] [OwnerOnly] public async Task MedusaLoad(string? name = null) @@ -190,13 +197,34 @@ public partial class Medusa : NadekoModule foreach (var medusa in medusae.Skip(page * 9).Take(9)) { eb.AddField(medusa.Name, - $@"`Sneks:` {medusa.Sneks.Count} -`Commands:` {medusa.Sneks.Sum(x => x.Commands.Count)} --- -{medusa.Description}"); + $""" + `Sneks:` {medusa.Sneks.Count} + `Commands:` {medusa.Sneks.Sum(x => x.Commands.Count)} + -- + {medusa.Description} + """); } return eb; }, medusae.Count, 9); } + + [Cmd] + [OwnerOnly] + public async Task MedusaSearch() + { + var eb = _eb.Create() + .WithTitle(GetText(strs.list_of_medusae)) + .WithOkColor(); + + foreach (var item in await _repo.GetModuleItemsAsync()) + { + eb.AddField(item.Name, $""" + {item.Description} + `{item.Command}` + """, true); + } + + await ctx.Channel.EmbedAsync(eb); + } } \ No newline at end of file diff --git a/src/NadekoBot/Modules/Medusae/MedusaItem.cs b/src/NadekoBot/Modules/Medusae/MedusaItem.cs new file mode 100644 index 000000000..beffb6cfb --- /dev/null +++ b/src/NadekoBot/Modules/Medusae/MedusaItem.cs @@ -0,0 +1,6 @@ +public class ModuleItem +{ + public string Name { get; init; } + public string Description { get; init; } + public string Command { get; init; } +} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Medusae/MedusaeRepositoryService.cs b/src/NadekoBot/Modules/Medusae/MedusaeRepositoryService.cs new file mode 100644 index 000000000..08c4be005 --- /dev/null +++ b/src/NadekoBot/Modules/Medusae/MedusaeRepositoryService.cs @@ -0,0 +1,22 @@ +namespace NadekoBot.Modules; + +public class MedusaeRepositoryService : IMedusaeRepositoryService, INService +{ + public async Task> GetModuleItemsAsync() + { + // Simulate retrieving data from a database or API + await Task.Delay(100); + return new List + { + new ModuleItem { Name = "RSS Reader", Description = "Keep up to date with your favorite websites", Command = ".meinstall rss" }, + new ModuleItem { Name = "Password Manager", Description = "Safely store and manage all your passwords", Command = ".meinstall passwordmanager" }, + new ModuleItem { Name = "Browser Extension", Description = "Enhance your browsing experience with useful tools", Command = ".meinstall browserextension" }, + new ModuleItem { Name = "Video Downloader", Description = "Download videos from popular websites", Command = ".meinstall videodownloader" }, + new ModuleItem { Name = "Virtual Private Network", Description = "Securely browse the web and protect your privacy", Command = ".meinstall vpn" }, + new ModuleItem { Name = "Ad Blocker", Description = "Block annoying ads and improve page load times", Command = ".meinstall adblocker" }, + new ModuleItem { Name = "Cloud Storage", Description = "Store and share your files online", Command = ".meinstall cloudstorage" }, + new ModuleItem { Name = "Social Media Manager", Description = "Manage all your social media accounts in one place", Command = ".meinstall socialmediamanager" }, + new ModuleItem { Name = "Code Editor", Description = "Write and edit code online", Command = ".meinstall codeeditor" } + }; + } +} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Medusae/ModuleItem.cs b/src/NadekoBot/Modules/Medusae/ModuleItem.cs new file mode 100644 index 000000000..0aac10051 --- /dev/null +++ b/src/NadekoBot/Modules/Medusae/ModuleItem.cs @@ -0,0 +1,8 @@ +namespace NadekoBot.Modules; + +public class ModuleItem +{ + public string Name { get; init; } + public string Description { get; init; } + public string Command { get; init; } +} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Nsfw/ISearchImagesService.cs b/src/NadekoBot/Modules/Nsfw/ISearchImagesService.cs deleted file mode 100644 index 98df23b70..000000000 --- a/src/NadekoBot/Modules/Nsfw/ISearchImagesService.cs +++ /dev/null @@ -1,27 +0,0 @@ -#nullable disable -using NadekoBot.Modules.Searches.Common; - -namespace NadekoBot.Modules.Nsfw; - -public interface ISearchImagesService -{ - ConcurrentDictionary AutoHentaiTimers { get; } - ConcurrentDictionary AutoBoobTimers { get; } - ConcurrentDictionary AutoButtTimers { get; } - Task Gelbooru(ulong? guildId, bool forceExplicit, string[] tags); - Task Danbooru(ulong? guildId, bool forceExplicit, string[] tags); - Task Konachan(ulong? guildId, bool forceExplicit, string[] tags); - Task Yandere(ulong? guildId, bool forceExplicit, string[] tags); - Task Rule34(ulong? guildId, bool forceExplicit, string[] tags); - Task E621(ulong? guildId, bool forceExplicit, string[] tags); - Task DerpiBooru(ulong? guildId, bool forceExplicit, string[] tags); - Task Sankaku(ulong? guildId, bool forceExplicit, string[] tags); - Task SafeBooru(ulong? guildId, bool forceExplicit, string[] tags); - Task Hentai(ulong? guildId, bool forceExplicit, string[] tags); - Task Boobs(); - ValueTask ToggleBlacklistTag(ulong guildId, string tag); - ValueTask GetBlacklistedTags(ulong guildId); - Task Butts(); - // Task GetNhentaiByIdAsync(uint id); - // Task GetNhentaiBySearchAsync(string search); -} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Nsfw/Nhentai/INhentaiService.cs b/src/NadekoBot/Modules/Nsfw/Nhentai/INhentaiService.cs deleted file mode 100644 index f2ea05260..000000000 --- a/src/NadekoBot/Modules/Nsfw/Nhentai/INhentaiService.cs +++ /dev/null @@ -1,9 +0,0 @@ -// using NadekoBot.Modules.Searches.Common; -// -// namespace NadekoBot.Modules.Nsfw; -// -// public interface INhentaiService -// { -// Task GetAsync(uint id); -// Task> GetIdsBySearchAsync(string search); -// } \ No newline at end of file diff --git a/src/NadekoBot/Modules/Nsfw/Nhentai/NhentaiScraperService.cs b/src/NadekoBot/Modules/Nsfw/Nhentai/NhentaiScraperService.cs deleted file mode 100644 index 35cfc708f..000000000 --- a/src/NadekoBot/Modules/Nsfw/Nhentai/NhentaiScraperService.cs +++ /dev/null @@ -1,115 +0,0 @@ -// using AngleSharp.Html.Dom; -// using AngleSharp.Html.Parser; -// using NadekoBot.Modules.Searches.Common; -// -// namespace NadekoBot.Modules.Nsfw; -// -// public sealed class NhentaiScraperService : INhentaiService, INService -// { -// private readonly IHttpClientFactory _httpFactory; -// -// private static readonly HtmlParser _htmlParser = new(new() -// { -// IsScripting = false, -// IsEmbedded = false, -// IsSupportingProcessingInstructions = false, -// IsKeepingSourceReferences = false, -// IsNotSupportingFrames = true -// }); -// -// public NhentaiScraperService(IHttpClientFactory httpFactory) -// { -// _httpFactory = httpFactory; -// } -// -// private HttpClient GetHttpClient() -// { -// var http = _httpFactory.CreateClient(); -// http.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.114 Safari/537.36"); -// http.DefaultRequestHeaders.Add("Cookie", "cf_clearance=I5pR71P4wJkRBFTLFjBndI.GwfKwT.Gx06uS8XNmRJo-1657214595-0-150; csrftoken=WMWRLtsQtBVQYvYkbqXKJHI9T1JwWCdd3tNhoxHn7aHLUYHAqe60XFUKAoWsJtda"); -// return http; -// } -// -// public async Task GetAsync(uint id) -// { -// using var http = GetHttpClient(); -// try -// { -// var url = $"https://nhentai.net/g/{id}/"; -// var strRes = await http.GetStringAsync(url); -// var doc = await _htmlParser.ParseDocumentAsync(strRes); -// -// var title = doc.QuerySelector("#info .title")?.TextContent; -// var fullTitle = doc.QuerySelector("meta[itemprop=\"name\"]")?.Attributes["content"]?.Value -// ?? title; -// var thumb = (doc.QuerySelector("#cover a img") as IHtmlImageElement)?.Dataset["src"]; -// -// var tagsElem = doc.QuerySelector("#tags"); -// -// var pageCount = tagsElem?.QuerySelector("a.tag[href^=\"/search/?q=pages\"] span")?.TextContent; -// var likes = doc.QuerySelector(".buttons .btn-disabled.btn.tooltip span span")?.TextContent?.Trim('(', ')'); -// var uploadedAt = (tagsElem?.QuerySelector(".tag-container .tags time.nobold") as IHtmlTimeElement)?.DateTime; -// -// var tags = tagsElem?.QuerySelectorAll(".tag-container .tags > a.tag[href^=\"/tag\"]") -// .Cast() -// .Select(x => new Tag() -// { -// Name = x.QuerySelector("span:first-child")?.TextContent, -// Url = $"https://nhentai.net{x.PathName}" -// }) -// .ToArray(); -// -// if (string.IsNullOrWhiteSpace(fullTitle)) -// return null; -// -// if (!int.TryParse(pageCount, out var pc)) -// return null; -// -// if (!int.TryParse(likes, out var lc)) -// return null; -// -// if (!DateTime.TryParse(uploadedAt, out var ua)) -// return null; -// -// return new Gallery(id, -// url, -// fullTitle, -// title, -// thumb, -// pc, -// lc, -// ua, -// tags); -// } -// catch (HttpRequestException) -// { -// Log.Warning("Nhentai with id {NhentaiId} not found", id); -// return null; -// } -// } -// -// public async Task> GetIdsBySearchAsync(string search) -// { -// using var http = GetHttpClient(); -// try -// { -// var url = $"https://nhentai.net/search/?q={Uri.EscapeDataString(search)}&sort=popular-today"; -// var strRes = await http.GetStringAsync(url); -// var doc = await _htmlParser.ParseDocumentAsync(strRes); -// -// var elems = doc.QuerySelectorAll(".container .gallery a") -// .Cast() -// .Where(x => x.PathName.StartsWith("/g/")) -// .Select(x => x.PathName[3..^1]) -// .Select(uint.Parse) -// .ToArray(); -// -// return elems; -// } -// catch (HttpRequestException) -// { -// Log.Warning("Nhentai search for {NhentaiSearch} failed", search); -// return Array.Empty(); -// } -// } -// } \ No newline at end of file diff --git a/src/NadekoBot/Modules/Nsfw/Nsfw.cs b/src/NadekoBot/Modules/Nsfw/Nsfw.cs deleted file mode 100644 index 0dfd1d7d8..000000000 --- a/src/NadekoBot/Modules/Nsfw/Nsfw.cs +++ /dev/null @@ -1,444 +0,0 @@ -#nullable disable -using Nadeko.Common; -using NadekoBot.Modules.Searches.Common; -using Newtonsoft.Json.Linq; - -namespace NadekoBot.Modules.Nsfw; - -#if !GLOBAL_NADEKO -[NoPublicBot] -public partial class NSFW : NadekoModule -{ - private static readonly ConcurrentHashSet _hentaiBombBlacklist = new(); - private readonly IHttpClientFactory _httpFactory; - private readonly NadekoRandom _rng; - - public NSFW(IHttpClientFactory factory) - { - _httpFactory = factory; - _rng = new(); - } - - private async Task InternalBoobs() - { - try - { - JToken obj; - using (var http = _httpFactory.CreateClient()) - { - obj = JArray.Parse( - await http.GetStringAsync($"http://api.oboobs.ru/boobs/{new NadekoRandom().Next(0, 10330)}"))[0]; - } - - await ctx.Channel.SendMessageAsync($"http://media.oboobs.ru/{obj["preview"]}"); - } - catch (Exception ex) - { - await SendErrorAsync(ex.Message); - } - } - - private async Task InternalButts(IMessageChannel channel) - { - try - { - JToken obj; - using (var http = _httpFactory.CreateClient()) - { - obj = JArray.Parse( - await http.GetStringAsync($"http://api.obutts.ru/butts/{new NadekoRandom().Next(0, 4335)}"))[0]; - } - - await channel.SendMessageAsync($"http://media.obutts.ru/{obj["preview"]}"); - } - catch (Exception ex) - { - await SendErrorAsync(ex.Message); - } - } - - [Cmd] - [RequireNsfw] - [RequireContext(ContextType.Guild)] - [UserPerm(ChannelPerm.ManageMessages)] - public async Task AutoHentai(int interval = 0, [Leftover] string tags = null) - { - Timer t; - - if (interval == 0) - { - if (!_service.AutoHentaiTimers.TryRemove(ctx.Channel.Id, out t)) - return; - - t.Change(Timeout.Infinite, Timeout.Infinite); //proper way to disable the timer - await ReplyConfirmLocalizedAsync(strs.stopped); - return; - } - - if (interval < 20) - return; - - t = new(async _ => - { - try - { - if (tags is null || tags.Length == 0) - await InternalDapiCommand(null, true, _service.Hentai); - else - { - var groups = tags.Split('|'); - var group = groups[_rng.Next(0, groups.Length)]; - await InternalDapiCommand(group.Split(' '), true, _service.Hentai); - } - } - catch - { - // ignored - } - }, - null, - interval * 1000, - interval * 1000); - - _service.AutoHentaiTimers.AddOrUpdate(ctx.Channel.Id, - t, - (_, old) => - { - old.Change(Timeout.Infinite, Timeout.Infinite); - return t; - }); - - await SendConfirmAsync($"Autohentai started. Interval: {interval}, Tags: {string.Join(", ", tags)}"); - } - - [Cmd] - [RequireNsfw] - [RequireContext(ContextType.Guild)] - [UserPerm(ChannelPerm.ManageMessages)] - public async Task AutoBoobs(int interval = 0) - { - Timer t; - - if (interval == 0) - { - if (!_service.AutoBoobTimers.TryRemove(ctx.Channel.Id, out t)) - return; - - t.Change(Timeout.Infinite, Timeout.Infinite); - await ReplyConfirmLocalizedAsync(strs.stopped); - return; - } - - if (interval < 20) - return; - - t = new(async _ => - { - try - { - await InternalBoobs(); - } - catch - { - // ignored - } - }, - null, - interval * 1000, - interval * 1000); - - _service.AutoBoobTimers.AddOrUpdate(ctx.Channel.Id, - t, - (_, old) => - { - old.Change(Timeout.Infinite, Timeout.Infinite); - return t; - }); - - await ReplyConfirmLocalizedAsync(strs.started(interval)); - } - - [Cmd] - [RequireNsfw(Group = "nsfw_or_dm")] - [RequireContext(ContextType.DM, Group = "nsfw_or_dm")] - [UserPerm(ChannelPerm.ManageMessages)] - public async Task AutoButts(int interval = 0) - { - Timer t; - - if (interval == 0) - { - if (!_service.AutoButtTimers.TryRemove(ctx.Channel.Id, out t)) - return; - - t.Change(Timeout.Infinite, Timeout.Infinite); //proper way to disable the timer - await ReplyConfirmLocalizedAsync(strs.stopped); - return; - } - - if (interval < 20) - return; - - t = new(async _ => - { - try - { - await InternalButts(ctx.Channel); - } - catch - { - // ignored - } - }, - null, - interval * 1000, - interval * 1000); - - _service.AutoButtTimers.AddOrUpdate(ctx.Channel.Id, - t, - (_, old) => - { - old.Change(Timeout.Infinite, Timeout.Infinite); - return t; - }); - - await ReplyConfirmLocalizedAsync(strs.started(interval)); - } - - [Cmd] - [RequireNsfw(Group = "nsfw_or_dm")] - [RequireContext(ContextType.DM, Group = "nsfw_or_dm")] - public Task Hentai(params string[] tags) - => InternalDapiCommand(tags, true, _service.Hentai); - - [Cmd] - [RequireNsfw(Group = "nsfw_or_dm")] - [RequireContext(ContextType.DM, Group = "nsfw_or_dm")] - public async Task HentaiBomb(params string[] tags) - { - if (!_hentaiBombBlacklist.Add(ctx.Guild?.Id ?? ctx.User.Id)) - return; - try - { - var images = await Task.WhenAll(_service.Yandere(ctx.Guild?.Id, true, tags), - _service.Danbooru(ctx.Guild?.Id, true, tags), - _service.Konachan(ctx.Guild?.Id, true, tags), - _service.Gelbooru(ctx.Guild?.Id, true, tags)); - - var linksEnum = images.Where(l => l is not null).ToArray(); - if (!linksEnum.Any()) - { - await ReplyErrorLocalizedAsync(strs.no_results); - return; - } - - await ctx.Channel.SendMessageAsync(string.Join("\n\n", linksEnum.Select(x => x.Url))); - } - finally - { - _hentaiBombBlacklist.TryRemove(ctx.Guild?.Id ?? ctx.User.Id); - } - } - - [Cmd] - [RequireNsfw(Group = "nsfw_or_dm")] - [RequireContext(ContextType.DM, Group = "nsfw_or_dm")] - public Task Yandere(params string[] tags) - => InternalDapiCommand(tags, false, _service.Yandere); - - [Cmd] - [RequireNsfw(Group = "nsfw_or_dm")] - [RequireContext(ContextType.DM, Group = "nsfw_or_dm")] - public Task Konachan(params string[] tags) - => InternalDapiCommand(tags, false, _service.Konachan); - - [Cmd] - [RequireNsfw(Group = "nsfw_or_dm")] - [RequireContext(ContextType.DM, Group = "nsfw_or_dm")] - public Task Sankaku(params string[] tags) - => InternalDapiCommand(tags, false, _service.Sankaku); - - [Cmd] - [RequireNsfw(Group = "nsfw_or_dm")] - [RequireContext(ContextType.DM, Group = "nsfw_or_dm")] - public Task E621(params string[] tags) - => InternalDapiCommand(tags, false, _service.E621); - - [Cmd] - [RequireNsfw(Group = "nsfw_or_dm")] - [RequireContext(ContextType.DM, Group = "nsfw_or_dm")] - public Task Rule34(params string[] tags) - => InternalDapiCommand(tags, false, _service.Rule34); - - [Cmd] - [RequireNsfw(Group = "nsfw_or_dm")] - [RequireContext(ContextType.DM, Group = "nsfw_or_dm")] - public Task Danbooru(params string[] tags) - => InternalDapiCommand(tags, false, _service.Danbooru); - - [Cmd] - [RequireNsfw(Group = "nsfw_or_dm")] - [RequireContext(ContextType.DM, Group = "nsfw_or_dm")] - public Task Gelbooru(params string[] tags) - => InternalDapiCommand(tags, false, _service.Gelbooru); - - [Cmd] - [RequireNsfw(Group = "nsfw_or_dm")] - [RequireContext(ContextType.DM, Group = "nsfw_or_dm")] - public Task Derpibooru(params string[] tags) - => InternalDapiCommand(tags, false, _service.DerpiBooru); - - [Cmd] - [RequireNsfw(Group = "nsfw_or_dm")] - [RequireContext(ContextType.DM, Group = "nsfw_or_dm")] - public Task Safebooru(params string[] tags) - => InternalDapiCommand(tags, false, _service.SafeBooru); - - [Cmd] - [RequireNsfw(Group = "nsfw_or_dm")] - [RequireContext(ContextType.DM, Group = "nsfw_or_dm")] - public async Task Boobs() - { - try - { - JToken obj; - using (var http = _httpFactory.CreateClient()) - { - obj = JArray.Parse( - await http.GetStringAsync($"http://api.oboobs.ru/boobs/{new NadekoRandom().Next(0, 12000)}"))[0]; - } - - await ctx.Channel.SendMessageAsync($"http://media.oboobs.ru/{obj["preview"]}"); - } - catch (Exception ex) - { - await SendErrorAsync(ex.Message); - } - } - - [Cmd] - [RequireNsfw(Group = "nsfw_or_dm")] - [RequireContext(ContextType.DM, Group = "nsfw_or_dm")] - public async Task Butts() - { - try - { - JToken obj; - using (var http = _httpFactory.CreateClient()) - { - obj = JArray.Parse( - await http.GetStringAsync($"http://api.obutts.ru/butts/{new NadekoRandom().Next(0, 6100)}"))[0]; - } - - await ctx.Channel.SendMessageAsync($"http://media.obutts.ru/{obj["preview"]}"); - } - catch (Exception ex) - { - await SendErrorAsync(ex.Message); - } - } - - [Cmd] - [RequireContext(ContextType.Guild)] - [UserPerm(GuildPerm.ManageMessages)] - public async Task NsfwTagBlacklist([Leftover] string tag = null) - { - if (string.IsNullOrWhiteSpace(tag)) - { - var blTags = await _service.GetBlacklistedTags(ctx.Guild.Id); - await SendConfirmAsync(GetText(strs.blacklisted_tag_list), blTags.Any() ? string.Join(", ", blTags) : "-"); - } - else - { - tag = tag.Trim().ToLowerInvariant(); - var added = await _service.ToggleBlacklistTag(ctx.Guild.Id, tag); - - if (added) - await ReplyPendingLocalizedAsync(strs.blacklisted_tag_add(tag)); - else - await ReplyPendingLocalizedAsync(strs.blacklisted_tag_remove(tag)); - } - } - - // [RequireNsfw(Group = "nsfw_or_dm")] - // [RequireContext(ContextType.DM, Group = "nsfw_or_dm")] - // [Priority(1)] - // public async Task Nhentai(uint id) - // { - // var g = await _service.GetNhentaiByIdAsync(id); - // - // if (g is null) - // { - // await ReplyErrorLocalizedAsync(strs.not_found); - // return; - // } - // - // await SendNhentaiGalleryInternalAsync(g); - // } - // - // [Cmd] - // [RequireContext(ContextType.Guild)] - // [RequireNsfw(Group = "nsfw_or_dm")] - // [RequireContext(ContextType.DM, Group = "nsfw_or_dm")] - // [Priority(0)] - // public async Task Nhentai([Leftover] string query) - // { - // var g = await _service.GetNhentaiBySearchAsync(query); - // - // if (g is null) - // { - // await ReplyErrorLocalizedAsync(strs.not_found); - // return; - // } - // - // await SendNhentaiGalleryInternalAsync(g); - // } - // - // private async Task SendNhentaiGalleryInternalAsync(Gallery g) - // { - // var count = 0; - // var tagString = g.Tags.Shuffle() - // .Select(tag => $"[{tag.Name}]({tag.Url})") - // .TakeWhile(tag => (count += tag.Length) < 1000) - // .Join(" "); - // - // var embed = _eb.Create() - // .WithTitle(g.Title) - // .WithDescription(g.FullTitle) - // .WithImageUrl(g.Thumbnail) - // .WithUrl(g.Url) - // .AddField(GetText(strs.favorites), g.Likes, true) - // .AddField(GetText(strs.pages), g.PageCount, true) - // .AddField(GetText(strs.tags), - // string.IsNullOrWhiteSpace(tagString) - // ? "?" - // : tagString, - // true) - // .WithFooter(g.UploadedAt.ToString("f")) - // .WithOkColor(); - // - // await ctx.Channel.EmbedAsync(embed); - // } - - private async Task InternalDapiCommand( - string[] tags, - bool forceExplicit, - Func> func) - { - var data = await func(ctx.Guild?.Id, forceExplicit, tags); - - if (data is null || !string.IsNullOrWhiteSpace(data.Error)) - { - await ReplyErrorLocalizedAsync(strs.no_results); - return; - } - - await ctx.Channel.EmbedAsync(_eb.Create(ctx) - .WithOkColor() - .WithImageUrl(data.Url) - .WithDescription($"[link]({data.Url})") - .WithFooter( - $"{data.Rating} ({data.Provider}) | {string.Join(" | ", data.Tags.Where(x => !string.IsNullOrWhiteSpace(x)).Take(5))}")); - } -} -#endif \ No newline at end of file diff --git a/src/NadekoBot/Modules/Nsfw/SearchImageCacher.cs b/src/NadekoBot/Modules/Nsfw/SearchImageCacher.cs deleted file mode 100644 index fb60382f4..000000000 --- a/src/NadekoBot/Modules/Nsfw/SearchImageCacher.cs +++ /dev/null @@ -1,320 +0,0 @@ -#nullable disable -using Microsoft.Extensions.Caching.Memory; -using Nadeko.Common; - -namespace NadekoBot.Modules.Nsfw.Common; - -public class SearchImageCacher : INService -{ - private static readonly ISet _defaultTagBlacklist = new HashSet - { - "loli", - "lolicon", - "shota", - "shotacon", - "cub" - }; - - private readonly IHttpClientFactory _httpFactory; - private readonly Random _rng; - - private readonly Dictionary _typeLocks = new(); - private readonly Dictionary> _usedTags = new(); - private readonly IMemoryCache _cache; - - private readonly ConcurrentDictionary<(Booru, string), int> _maxPages = new(); - - public SearchImageCacher(IHttpClientFactory httpFactory, IMemoryCache cache) - { - _httpFactory = httpFactory; - _rng = new NadekoRandom(); - _cache = cache; - - // initialize new cache with empty values - foreach (var type in Enum.GetValues()) - { - _typeLocks[type] = new(); - _usedTags[type] = new(); - } - } - - private string Key(Booru boory, string tag) - => $"booru:{boory}__tag:{tag}"; - - /// - /// Download images of the specified type, and cache them. - /// - /// Required tags - /// Whether images will be forced to be explicit - /// Provider type - /// Cancellation token - /// Whether any image is found. - private async Task UpdateImagesInternalAsync( - string[] tags, - bool forceExplicit, - Booru type, - CancellationToken cancel) - { - var images = await DownloadImagesAsync(tags, forceExplicit, type, cancel); - if (images is null || images.Count == 0) - // Log.Warning("Got no images for {0}, tags: {1}", type, string.Join(", ", tags)); - return false; - - Log.Information("Updating {Type}...", type); - lock (_typeLocks[type]) - { - var typeUsedTags = _usedTags[type]; - foreach (var tag in tags) - typeUsedTags.Add(tag); - - // if user uses no tags for the hentai command and there are no used - // tags atm, just select 50 random tags from downloaded images to seed - if (typeUsedTags.Count == 0) - images.SelectMany(x => x.Tags).Distinct().Shuffle().Take(50).ToList().ForEach(x => typeUsedTags.Add(x)); - - foreach (var img in images) - { - // if any of the tags is a tag banned by discord - // do not put that image in the cache - if (_defaultTagBlacklist.Overlaps(img.Tags)) - continue; - - // if image doesn't have a proper absolute uri, skip it - if (!Uri.IsWellFormedUriString(img.FileUrl, UriKind.Absolute)) - continue; - - // i'm appending current tags because of tag aliasing - // this way, if user uses tag alias, for example 'kissing' - - // both 'kiss' (real tag returned by the image) and 'kissing' will be populated with - // retreived images - foreach (var tag in img.Tags.Concat(tags).Distinct()) - { - if (typeUsedTags.Contains(tag)) - { - var set = _cache.GetOrCreate>(Key(type, tag), - e => - { - e.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(30); - return new(); - }); - - if (set.Count < 100) - set.Add(img); - } - } - } - } - - return true; - } - - private ImageData QueryLocal( - string[] tags, - Booru type, - HashSet blacklistedTags) - { - var setList = new List>(); - - // ofc make sure no changes are happening while we're getting a random one - lock (_typeLocks[type]) - { - // if no tags are provided, get a random tag - if (tags.Length == 0) - { - // get all tags in the cache - if (_usedTags.TryGetValue(type, out var allTags) && allTags.Count > 0) - tags = new[] { allTags.ToList()[_rng.Next(0, allTags.Count)] }; - else - return null; - } - - foreach (var tag in tags) - // if any tag is missing from cache, that means there is no result - { - if (_cache.TryGetValue>(Key(type, tag), out var set)) - setList.Add(set); - else - return null; - } - - if (setList.Count == 0) - return null; - - - List resultList; - // if multiple tags, we need to interesect sets - if (setList.Count > 1) - { - // now that we have sets, interesect them to find eligible items - // make a copy of the 1st set - var resultSet = new HashSet(setList[0]); - - // go through all other sets, and - for (var i = 1; i < setList.Count; ++i) - // if any of the elements in result set are not present in the current set - // remove it from the result set - resultSet.IntersectWith(setList[i]); - - resultList = resultSet.ToList(); - } - else - { - // if only one tag, use that set - resultList = setList[0].ToList(); - } - - // return a random one which doesn't have blacklisted tags in it - resultList = resultList.Where(x => !blacklistedTags.Overlaps(x.Tags)).ToList(); - - // if no items in the set -> not found - if (resultList.Count == 0) - return null; - - var toReturn = resultList[_rng.Next(0, resultList.Count)]; - - // remove from cache - foreach (var tag in tags) - { - if (_cache.TryGetValue>(Key(type, tag), out var items)) - items.Remove(toReturn); - } - - return toReturn; - } - } - - public async Task GetImageNew( - string[] tags, - bool forceExplicit, - Booru type, - HashSet blacklistedTags, - CancellationToken cancel) - { - // make sure tags are proper - tags = tags.Where(x => x is not null).Select(tag => tag.ToLowerInvariant().Trim()).Distinct().ToArray(); - - if (tags.Length > 2 && type == Booru.Danbooru) - tags = tags[..2]; - - // use both tags banned by discord and tags banned on the server - if (blacklistedTags.Overlaps(tags) || _defaultTagBlacklist.Overlaps(tags)) - return default; - - // query for an image - var image = QueryLocal(tags, type, blacklistedTags); - if (image is not null) - return image; - - var success = false; - try - { - // if image is not found, update the cache and query again - success = await UpdateImagesInternalAsync(tags, forceExplicit, type, cancel); - } - catch (HttpRequestException) - { - } - - if (!success) - return default; - - image = QueryLocal(tags, type, blacklistedTags); - - return image; - } - - public async Task> DownloadImagesAsync( - string[] tags, - bool isExplicit, - Booru type, - CancellationToken cancel) - { - var tagStr = string.Join(' ', tags.OrderByDescending(x => x)); - - var attempt = 0; - while (attempt++ <= 10) - { - int page; - if (_maxPages.TryGetValue((type, tagStr), out var maxPage)) - { - if (maxPage == 0) - { - Log.Information("Tag {Tags} yields no result on {Type}, skipping", tagStr, type); - return new(); - } - - page = _rng.Next(0, maxPage); - } - else - page = _rng.Next(0, 11); - - var result = await DownloadImagesAsync(tags, isExplicit, type, page, cancel); - - if (result is null or { Count: 0 }) - { - Log.Information("Tag {Tags}, page {Page} has no result on {Type}", - string.Join(", ", tags), - page, - type.ToString()); - continue; - } - - return result; - } - - return new(); - } - - private IImageDownloader GetImageDownloader(Booru booru) - => booru switch - { - Booru.Danbooru => new DanbooruImageDownloader(_httpFactory), - Booru.Yandere => new YandereImageDownloader(_httpFactory), - Booru.Konachan => new KonachanImageDownloader(_httpFactory), - Booru.Safebooru => new SafebooruImageDownloader(_httpFactory), - Booru.E621 => new E621ImageDownloader(_httpFactory), - Booru.Derpibooru => new DerpibooruImageDownloader(_httpFactory), - Booru.Gelbooru => new GelbooruImageDownloader(_httpFactory), - Booru.Rule34 => new Rule34ImageDownloader(_httpFactory), - Booru.Sankaku => new SankakuImageDownloader(_httpFactory), - _ => throw new NotImplementedException($"{booru} downloader not implemented.") - }; - - private async Task> DownloadImagesAsync( - string[] tags, - bool isExplicit, - Booru type, - int page, - CancellationToken cancel) - { - try - { - Log.Information("Downloading from {Type} (page {Page})...", type, page); - - var downloader = GetImageDownloader(type); - - var images = await downloader.DownloadImageDataAsync(tags, page, isExplicit, cancel); - if (images.Count == 0) - { - var tagStr = string.Join(' ', tags.OrderByDescending(x => x)); - _maxPages[(type, tagStr)] = page; - } - - return images; - } - catch (OperationCanceledException) - { - throw; - } - catch (Exception ex) - { - Log.Error(ex, - "Error downloading an image:\nTags: {Tags}\nType: {Type}\nPage: {Page}\nMessage: {Message}", - string.Join(", ", tags), - type, - page, - ex.Message); - return new(); - } - } -} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Nsfw/SearchImagesService.cs b/src/NadekoBot/Modules/Nsfw/SearchImagesService.cs deleted file mode 100644 index edf8c8851..000000000 --- a/src/NadekoBot/Modules/Nsfw/SearchImagesService.cs +++ /dev/null @@ -1,297 +0,0 @@ -#nullable disable warnings -using LinqToDB; -using Nadeko.Common; -using NadekoBot.Modules.Nsfw.Common; -using NadekoBot.Modules.Searches.Common; -using Newtonsoft.Json.Linq; - -namespace NadekoBot.Modules.Nsfw; - -public class SearchImagesService : ISearchImagesService, INService -{ - private ConcurrentDictionary> BlacklistedTags { get; } - - public ConcurrentDictionary AutoHentaiTimers { get; } = new(); - public ConcurrentDictionary AutoBoobTimers { get; } = new(); - public ConcurrentDictionary AutoButtTimers { get; } = new(); - - private readonly Random _rng; - private readonly SearchImageCacher _cache; - private readonly IHttpClientFactory _httpFactory; - private readonly DbService _db; - - private readonly object _taglock = new(); - - public SearchImagesService( - DbService db, - SearchImageCacher cacher, - IHttpClientFactory httpFactory - ) - { - _db = db; - _rng = new NadekoRandom(); - _cache = cacher; - _httpFactory = httpFactory; - - using var uow = db.GetDbContext(); - BlacklistedTags = new(uow.NsfwBlacklistedTags.AsEnumerable() - .GroupBy(x => x.GuildId) - .ToDictionary(x => x.Key, x => new HashSet(x.Select(y => y.Tag)))); - } - - private Task GetNsfwImageAsync( - ulong? guildId, - bool forceExplicit, - string[] tags, - Booru dapi, - CancellationToken cancel = default) - => GetNsfwImageAsync(guildId ?? 0, tags ?? Array.Empty(), forceExplicit, dapi, cancel); - - private bool IsValidTag(string tag) - => tag.All(x => x != '+' && x != '?' && x != '/'); // tags mustn't contain + or ? or / - - private async Task GetNsfwImageAsync( - ulong guildId, - string[] tags, - bool forceExplicit, - Booru dapi, - CancellationToken cancel) - { - if (!tags.All(x => IsValidTag(x))) - { - return new() - { - Error = "One or more tags are invalid.", - Url = "" - }; - } - - Log.Information("Getting {V} image for Guild: {GuildId}...", dapi.ToString(), guildId); - try - { - BlacklistedTags.TryGetValue(guildId, out var blTags); - - if (dapi == Booru.E621) - { - for (var i = 0; i < tags.Length; ++i) - { - if (tags[i] == "yuri") - tags[i] = "female/female"; - } - } - - if (dapi == Booru.Derpibooru) - { - for (var i = 0; i < tags.Length; ++i) - { - if (tags[i] == "yuri") - tags[i] = "lesbian"; - } - } - - var result = await _cache.GetImageNew(tags, forceExplicit, dapi, blTags ?? new HashSet(), cancel); - - if (result is null) - { - return new() - { - Error = "Image not found.", - Url = "" - }; - } - - var reply = new UrlReply - { - Error = "", - Url = result.FileUrl, - Rating = result.Rating, - Provider = result.SearchType.ToString() - }; - - reply.Tags.AddRange(result.Tags); - - return reply; - } - catch (Exception ex) - { - Log.Error(ex, "Failed getting {Dapi} image: {Message}", dapi, ex.Message); - return new() - { - Error = ex.Message, - Url = "" - }; - } - } - - public Task Gelbooru(ulong? guildId, bool forceExplicit, string[] tags) - => GetNsfwImageAsync(guildId, forceExplicit, tags, Booru.Gelbooru); - - public Task Danbooru(ulong? guildId, bool forceExplicit, string[] tags) - => GetNsfwImageAsync(guildId, forceExplicit, tags, Booru.Danbooru); - - public Task Konachan(ulong? guildId, bool forceExplicit, string[] tags) - => GetNsfwImageAsync(guildId, forceExplicit, tags, Booru.Konachan); - - public Task Yandere(ulong? guildId, bool forceExplicit, string[] tags) - => GetNsfwImageAsync(guildId, forceExplicit, tags, Booru.Yandere); - - public Task Rule34(ulong? guildId, bool forceExplicit, string[] tags) - => GetNsfwImageAsync(guildId, forceExplicit, tags, Booru.Rule34); - - public Task E621(ulong? guildId, bool forceExplicit, string[] tags) - => GetNsfwImageAsync(guildId, forceExplicit, tags, Booru.E621); - - public Task DerpiBooru(ulong? guildId, bool forceExplicit, string[] tags) - => GetNsfwImageAsync(guildId, forceExplicit, tags, Booru.Derpibooru); - - public Task SafeBooru(ulong? guildId, bool forceExplicit, string[] tags) - => GetNsfwImageAsync(guildId, forceExplicit, tags, Booru.Safebooru); - - public Task Sankaku(ulong? guildId, bool forceExplicit, string[] tags) - => GetNsfwImageAsync(guildId, forceExplicit, tags, Booru.Sankaku); - - public async Task Hentai(ulong? guildId, bool forceExplicit, string[] tags) - { - var providers = new[] { Booru.Danbooru, Booru.Konachan, Booru.Gelbooru, Booru.Yandere }; - - using var cancelSource = new CancellationTokenSource(); - - // create a task for each type - var tasks = providers.Select(type => GetNsfwImageAsync(guildId, forceExplicit, tags, type)).ToList(); - do - { - // wait for any of the tasks to complete - var task = await Task.WhenAny(tasks); - - // get its result - var result = task.GetAwaiter().GetResult(); - if (result.Error == "") - { - // if we have a non-error result, cancel other searches and return the result - cancelSource.Cancel(); - return result; - } - - // if the result is an error, remove that task from the waiting list, - // and wait for another task to complete - tasks.Remove(task); - } while (tasks.Count > 0); // keep looping as long as there is any task remaining to be attempted - - // if we ran out of tasks, that means all tasks failed - return an error - return new() - { - Error = "No hentai image found." - }; - } - - public async Task Boobs() - { - try - { - using var http = _httpFactory.CreateClient(); - http.AddFakeHeaders(); - JToken obj; - obj = JArray.Parse(await http.GetStringAsync($"http://api.oboobs.ru/boobs/{_rng.Next(0, 12000)}"))[0]; - return new() - { - Error = "", - Url = $"http://media.oboobs.ru/{obj["preview"]}" - }; - } - catch (Exception ex) - { - Log.Error(ex, "Error retreiving boob image: {Message}", ex.Message); - return new() - { - Error = ex.Message, - Url = "" - }; - } - } - - public ValueTask ToggleBlacklistTag(ulong guildId, string tag) - { - lock (_taglock) - { - tag = tag.Trim().ToLowerInvariant(); - var blacklistedTags = BlacklistedTags.GetOrAdd(guildId, new HashSet()); - var isAdded = blacklistedTags.Add(tag); - - using var uow = _db.GetDbContext(); - if (!isAdded) - { - blacklistedTags.Remove(tag); - uow.NsfwBlacklistedTags.DeleteAsync(x => x.GuildId == guildId && x.Tag == tag); - uow.SaveChanges(); - } - else - { - uow.NsfwBlacklistedTags.Add(new() - { - Tag = tag, - GuildId = guildId - }); - - uow.SaveChanges(); - } - - return new(isAdded); - } - } - - public ValueTask GetBlacklistedTags(ulong guildId) - { - lock (_taglock) - { - if (BlacklistedTags.TryGetValue(guildId, out var tags)) - return new(tags.ToArray()); - - return new(Array.Empty()); - } - } - - public async Task Butts() - { - try - { - using var http = _httpFactory.CreateClient(); - http.AddFakeHeaders(); - JToken obj; - obj = JArray.Parse(await http.GetStringAsync($"http://api.obutts.ru/butts/{_rng.Next(0, 6100)}"))[0]; - return new() - { - Error = "", - Url = $"http://media.obutts.ru/{obj["preview"]}" - }; - } - catch (Exception ex) - { - Log.Error(ex, "Error retreiving butt image: {Message}", ex.Message); - return new() - { - Error = ex.Message, - Url = "" - }; - } - } - - /* - #region Nhentai - - public Task GetNhentaiByIdAsync(uint id) - => _nh.GetAsync(id); - - public async Task GetNhentaiBySearchAsync(string search) - { - var ids = await _nh.GetIdsBySearchAsync(search); - - if (ids.Count == 0) - return null; - - var id = ids[_rng.Next(0, ids.Count)]; - return await _nh.GetAsync(id); - } - - #endregion - */ -} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Nsfw/UrlReply.cs b/src/NadekoBot/Modules/Nsfw/UrlReply.cs deleted file mode 100644 index c442bea94..000000000 --- a/src/NadekoBot/Modules/Nsfw/UrlReply.cs +++ /dev/null @@ -1,11 +0,0 @@ -#nullable disable warnings -namespace NadekoBot.Modules.Nsfw; - -public record UrlReply -{ - public string Error { get; init; } - public string Url { get; init; } - public string Rating { get; init; } - public string Provider { get; init; } - public List Tags { get; } = new(); -} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Nsfw/_Common/Booru.cs b/src/NadekoBot/Modules/Nsfw/_Common/Booru.cs deleted file mode 100644 index 2c92ccee6..000000000 --- a/src/NadekoBot/Modules/Nsfw/_Common/Booru.cs +++ /dev/null @@ -1,15 +0,0 @@ -#nullable disable -namespace NadekoBot.Modules.Nsfw.Common; - -public enum Booru -{ - Safebooru, - E621, - Derpibooru, - Rule34, - Gelbooru, - Konachan, - Yandere, - Danbooru, - Sankaku -} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Nsfw/_Common/DapiImageObject.cs b/src/NadekoBot/Modules/Nsfw/_Common/DapiImageObject.cs deleted file mode 100644 index 1e852fd20..000000000 --- a/src/NadekoBot/Modules/Nsfw/_Common/DapiImageObject.cs +++ /dev/null @@ -1,21 +0,0 @@ -#nullable disable -using System.Text.Json.Serialization; - -namespace NadekoBot.Modules.Nsfw.Common; - -public class DapiImageObject : IImageData -{ - [JsonPropertyName("File_Url")] - public string FileUrl { get; set; } - - public string Tags { get; set; } - - [JsonPropertyName("Tag_String")] - public string TagString { get; set; } - - public int Score { get; set; } - public string Rating { get; set; } - - public ImageData ToCachedImageData(Booru type) - => new(FileUrl, type, Tags?.Split(' ') ?? TagString?.Split(' '), Score.ToString() ?? Rating); -} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Nsfw/_Common/DapiTag.cs b/src/NadekoBot/Modules/Nsfw/_Common/DapiTag.cs deleted file mode 100644 index 3febac369..000000000 --- a/src/NadekoBot/Modules/Nsfw/_Common/DapiTag.cs +++ /dev/null @@ -1,13 +0,0 @@ -#nullable disable -using System.Text.Json.Serialization; - -namespace NadekoBot.Modules.Nsfw.Common; - -public readonly struct DapiTag -{ - public string Name { get; } - - [JsonConstructor] - public DapiTag(string name) - => Name = name; -} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Nsfw/_Common/DerpiContainer.cs b/src/NadekoBot/Modules/Nsfw/_Common/DerpiContainer.cs deleted file mode 100644 index f6c41226f..000000000 --- a/src/NadekoBot/Modules/Nsfw/_Common/DerpiContainer.cs +++ /dev/null @@ -1,21 +0,0 @@ -#nullable disable -using System.Text.Json.Serialization; - -namespace NadekoBot.Modules.Nsfw.Common; - -public class DerpiContainer -{ - public DerpiImageObject[] Images { get; set; } -} - -public class DerpiImageObject : IImageData -{ - [JsonPropertyName("view_url")] - public string ViewUrl { get; set; } - - public string[] Tags { get; set; } - public int Score { get; set; } - - public ImageData ToCachedImageData(Booru type) - => new(ViewUrl, type, Tags, Score.ToString("F1")); -} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Nsfw/_Common/Downloaders/DanbooruImageDownloader.cs b/src/NadekoBot/Modules/Nsfw/_Common/Downloaders/DanbooruImageDownloader.cs deleted file mode 100644 index 35566c68d..000000000 --- a/src/NadekoBot/Modules/Nsfw/_Common/Downloaders/DanbooruImageDownloader.cs +++ /dev/null @@ -1,35 +0,0 @@ -#nullable disable -using System.Net.Http.Json; - -namespace NadekoBot.Modules.Nsfw.Common; - -public sealed class DanbooruImageDownloader : DapiImageDownloader -{ - // using them as concurrent hashsets, value doesn't matter - private static readonly ConcurrentDictionary _existentTags = new(); - private static readonly ConcurrentDictionary _nonexistentTags = new(); - - public DanbooruImageDownloader(IHttpClientFactory http) - : base(Booru.Danbooru, http, "http://danbooru.donmai.us") - { - } - - public override async Task IsTagValid(string tag, CancellationToken cancel = default) - { - if (_existentTags.ContainsKey(tag)) - return true; - - if (_nonexistentTags.ContainsKey(tag)) - return false; - - using var http = _http.CreateClient(); - var tags = await http.GetFromJsonAsync( - _baseUrl + "/tags.json" + $"?search[name_or_alias_matches]={tag}", - _serializerOptions, - cancel); - if (tags is { Length: > 0 }) - return _existentTags[tag] = true; - - return _nonexistentTags[tag] = false; - } -} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Nsfw/_Common/Downloaders/DapiImageDownloader.cs b/src/NadekoBot/Modules/Nsfw/_Common/Downloaders/DapiImageDownloader.cs deleted file mode 100644 index 2b08414a9..000000000 --- a/src/NadekoBot/Modules/Nsfw/_Common/Downloaders/DapiImageDownloader.cs +++ /dev/null @@ -1,53 +0,0 @@ -#nullable disable -using System.Net.Http.Json; -using Nadeko.Common; - -namespace NadekoBot.Modules.Nsfw.Common; - -public abstract class DapiImageDownloader : ImageDownloader -{ - protected readonly string _baseUrl; - - public DapiImageDownloader(Booru booru, IHttpClientFactory http, string baseUrl) - : base(booru, http) - => _baseUrl = baseUrl; - - public abstract Task IsTagValid(string tag, CancellationToken cancel = default); - - protected async Task AllTagsValid(string[] tags, CancellationToken cancel = default) - { - var results = await tags.Select(tag => IsTagValid(tag, cancel)).WhenAll(); - - // if any of the tags is not valid, the query is not valid - foreach (var result in results) - { - if (!result) - return false; - } - - return true; - } - - public override async Task> DownloadImagesAsync( - string[] tags, - int page, - bool isExplicit = false, - CancellationToken cancel = default) - { - // up to 2 tags allowed on danbooru - if (tags.Length > 2) - return new(); - - if (!await AllTagsValid(tags, cancel)) - return new(); - - var tagString = ImageDownloaderHelper.GetTagString(tags, isExplicit); - - var uri = $"{_baseUrl}/posts.json?limit=200&tags={tagString}&page={page}"; - using var http = _http.CreateClient(); - var imageObjects = await http.GetFromJsonAsync(uri, _serializerOptions, cancel); - if (imageObjects is null) - return new(); - return imageObjects.Where(x => x.FileUrl is not null).ToList(); - } -} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Nsfw/_Common/Downloaders/DerpibooruImageDownloader.cs b/src/NadekoBot/Modules/Nsfw/_Common/Downloaders/DerpibooruImageDownloader.cs deleted file mode 100644 index 7ef7eaccf..000000000 --- a/src/NadekoBot/Modules/Nsfw/_Common/Downloaders/DerpibooruImageDownloader.cs +++ /dev/null @@ -1,35 +0,0 @@ -#nullable disable -using System.Net.Http.Json; -using Nadeko.Common; - -namespace NadekoBot.Modules.Nsfw.Common; - -public class DerpibooruImageDownloader : ImageDownloader -{ - public DerpibooruImageDownloader(IHttpClientFactory http) - : base(Booru.Derpibooru, http) - { - } - - public override async Task> DownloadImagesAsync( - string[] tags, - int page, - bool isExplicit = false, - CancellationToken cancel = default) - { - var tagString = ImageDownloaderHelper.GetTagString(tags, isExplicit); - var uri = - $"https://www.derpibooru.org/api/v1/json/search/images?q={tagString.Replace('+', ',')}&per_page=49&page={page}"; - using var req = new HttpRequestMessage(HttpMethod.Get, uri); - req.Headers.AddFakeHeaders(); - using var http = _http.CreateClient(); - using var res = await http.SendAsync(req, cancel); - res.EnsureSuccessStatusCode(); - - var container = await res.Content.ReadFromJsonAsync(_serializerOptions, cancel); - if (container?.Images is null) - return new(); - - return container.Images.Where(x => !string.IsNullOrWhiteSpace(x.ViewUrl)).ToList(); - } -} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Nsfw/_Common/Downloaders/E621ImageDownloader.cs b/src/NadekoBot/Modules/Nsfw/_Common/Downloaders/E621ImageDownloader.cs deleted file mode 100644 index 18b792e4f..000000000 --- a/src/NadekoBot/Modules/Nsfw/_Common/Downloaders/E621ImageDownloader.cs +++ /dev/null @@ -1,34 +0,0 @@ -#nullable disable -using System.Net.Http.Json; -using Nadeko.Common; - -namespace NadekoBot.Modules.Nsfw.Common; - -public class E621ImageDownloader : ImageDownloader -{ - public E621ImageDownloader(IHttpClientFactory http) - : base(Booru.E621, http) - { - } - - public override async Task> DownloadImagesAsync( - string[] tags, - int page, - bool isExplicit = false, - CancellationToken cancel = default) - { - var tagString = ImageDownloaderHelper.GetTagString(tags, isExplicit); - var uri = $"https://e621.net/posts.json?limit=32&tags={tagString}&page={page}"; - using var req = new HttpRequestMessage(HttpMethod.Get, uri); - req.Headers.AddFakeHeaders(); - using var http = _http.CreateClient(); - using var res = await http.SendAsync(req, cancel); - res.EnsureSuccessStatusCode(); - - var data = await res.Content.ReadFromJsonAsync(_serializerOptions, cancel); - if (data?.Posts is null) - return new(); - - return data.Posts.Where(x => !string.IsNullOrWhiteSpace(x.File?.Url)).ToList(); - } -} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Nsfw/_Common/Downloaders/E621Response.cs b/src/NadekoBot/Modules/Nsfw/_Common/Downloaders/E621Response.cs deleted file mode 100644 index 4d29b9aff..000000000 --- a/src/NadekoBot/Modules/Nsfw/_Common/Downloaders/E621Response.cs +++ /dev/null @@ -1,7 +0,0 @@ -#nullable disable -namespace NadekoBot.Modules.Nsfw.Common; - -public class E621Response -{ - public List Posts { get; set; } -} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Nsfw/_Common/Downloaders/GelbooruImageDownloader.cs b/src/NadekoBot/Modules/Nsfw/_Common/Downloaders/GelbooruImageDownloader.cs deleted file mode 100644 index bd957186f..000000000 --- a/src/NadekoBot/Modules/Nsfw/_Common/Downloaders/GelbooruImageDownloader.cs +++ /dev/null @@ -1,48 +0,0 @@ -#nullable disable -using System.Text.Json; -using System.Text.Json.Serialization; - -namespace NadekoBot.Modules.Nsfw.Common; - -public class GelbooruImageDownloader : ImageDownloader -{ - public GelbooruImageDownloader(IHttpClientFactory http) - : base(Booru.Gelbooru, http) - { - } - - public override async Task> DownloadImagesAsync( - string[] tags, - int page, - bool isExplicit = false, - CancellationToken cancel = default) - { - var tagString = ImageDownloaderHelper.GetTagString(tags, isExplicit); - var uri = $"https://gelbooru.com/index.php?page=dapi" - + $"&s=post" - + $"&json=1" - + $"&q=index" - + $"&limit=100" - + $"&tags={tagString}" - + $"&pid={page}"; - using var req = new HttpRequestMessage(HttpMethod.Get, uri); - using var http = _http.CreateClient(); - using var res = await http.SendAsync(req, cancel); - res.EnsureSuccessStatusCode(); - var resString = await res.Content.ReadAsStringAsync(cancel); - if (string.IsNullOrWhiteSpace(resString)) - return new(); - - var images = JsonSerializer.Deserialize(resString, _serializerOptions); - if (images is null or { Post: null }) - return new(); - - return images.Post.Where(x => x.FileUrl is not null).ToList(); - } -} - -public class GelbooruResponse -{ - [JsonPropertyName("post")] - public List Post { get; set; } -} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Nsfw/_Common/Downloaders/IImageDownloader.cs b/src/NadekoBot/Modules/Nsfw/_Common/Downloaders/IImageDownloader.cs deleted file mode 100644 index 9529a4614..000000000 --- a/src/NadekoBot/Modules/Nsfw/_Common/Downloaders/IImageDownloader.cs +++ /dev/null @@ -1,11 +0,0 @@ -#nullable disable -namespace NadekoBot.Modules.Nsfw.Common; - -public interface IImageDownloader -{ - Task> DownloadImageDataAsync( - string[] tags, - int page = 0, - bool isExplicit = false, - CancellationToken cancel = default); -} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Nsfw/_Common/Downloaders/ImageDownloader.cs b/src/NadekoBot/Modules/Nsfw/_Common/Downloaders/ImageDownloader.cs deleted file mode 100644 index 045335cca..000000000 --- a/src/NadekoBot/Modules/Nsfw/_Common/Downloaders/ImageDownloader.cs +++ /dev/null @@ -1,40 +0,0 @@ -#nullable disable -using System.Text.Json; -using System.Text.Json.Serialization; - -namespace NadekoBot.Modules.Nsfw.Common; - -public abstract class ImageDownloader : IImageDownloader - where T : IImageData -{ - public Booru Booru { get; } - protected readonly IHttpClientFactory _http; - - protected readonly JsonSerializerOptions _serializerOptions = new() - { - PropertyNameCaseInsensitive = true, - NumberHandling = JsonNumberHandling.WriteAsString | JsonNumberHandling.AllowReadingFromString - }; - - public ImageDownloader(Booru booru, IHttpClientFactory http) - { - _http = http; - Booru = booru; - } - - public abstract Task> DownloadImagesAsync( - string[] tags, - int page, - bool isExplicit = false, - CancellationToken cancel = default); - - public async Task> DownloadImageDataAsync( - string[] tags, - int page, - bool isExplicit = false, - CancellationToken cancel = default) - { - var images = await DownloadImagesAsync(tags, page, isExplicit, cancel); - return images.Select(x => x.ToCachedImageData(Booru)).ToList(); - } -} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Nsfw/_Common/Downloaders/ImageDownloaderHelper.cs b/src/NadekoBot/Modules/Nsfw/_Common/Downloaders/ImageDownloaderHelper.cs deleted file mode 100644 index 3bf8ef7af..000000000 --- a/src/NadekoBot/Modules/Nsfw/_Common/Downloaders/ImageDownloaderHelper.cs +++ /dev/null @@ -1,13 +0,0 @@ -#nullable disable -namespace NadekoBot.Modules.Nsfw.Common; - -public static class ImageDownloaderHelper -{ - public static string GetTagString(IEnumerable tags, bool isExplicit = false) - { - if (isExplicit) - tags = tags.Append("rating:explicit"); - - return string.Join('+', tags.Select(x => x.ToLowerInvariant())); - } -} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Nsfw/_Common/Downloaders/KonachanImageDownloader.cs b/src/NadekoBot/Modules/Nsfw/_Common/Downloaders/KonachanImageDownloader.cs deleted file mode 100644 index 0c649ee10..000000000 --- a/src/NadekoBot/Modules/Nsfw/_Common/Downloaders/KonachanImageDownloader.cs +++ /dev/null @@ -1,28 +0,0 @@ -#nullable disable -using System.Net.Http.Json; - -namespace NadekoBot.Modules.Nsfw.Common; - -public sealed class KonachanImageDownloader : ImageDownloader -{ - private readonly string _baseUrl; - - public KonachanImageDownloader(IHttpClientFactory http) - : base(Booru.Konachan, http) - => _baseUrl = "https://konachan.com"; - - public override async Task> DownloadImagesAsync( - string[] tags, - int page, - bool isExplicit = false, - CancellationToken cancel = default) - { - var tagString = ImageDownloaderHelper.GetTagString(tags, isExplicit); - var uri = $"{_baseUrl}/post.json?s=post&q=index&limit=200&tags={tagString}&page={page}"; - using var http = _http.CreateClient(); - var imageObjects = await http.GetFromJsonAsync(uri, _serializerOptions, cancel); - if (imageObjects is null) - return new(); - return imageObjects.Where(x => x.FileUrl is not null).ToList(); - } -} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Nsfw/_Common/Downloaders/Rule34ImageDownloader.cs b/src/NadekoBot/Modules/Nsfw/_Common/Downloaders/Rule34ImageDownloader.cs deleted file mode 100644 index 3d0aaaeff..000000000 --- a/src/NadekoBot/Modules/Nsfw/_Common/Downloaders/Rule34ImageDownloader.cs +++ /dev/null @@ -1,41 +0,0 @@ -#nullable disable -using System.Net.Http.Json; - -namespace NadekoBot.Modules.Nsfw.Common; - -public class Rule34ImageDownloader : ImageDownloader -{ - public Rule34ImageDownloader(IHttpClientFactory http) - : base(Booru.Rule34, http) - { - } - - public override async Task> DownloadImagesAsync( - string[] tags, - int page, - bool isExplicit = false, - CancellationToken cancel = default) - { - var tagString = ImageDownloaderHelper.GetTagString(tags); - var uri = $"https://api.rule34.xxx//index.php?page=dapi&s=post" - + $"&q=index" - + $"&json=1" - + $"&limit=100" - + $"&tags={tagString}" - + $"&pid={page}"; - - using var http = _http.CreateClient(); - http.DefaultRequestHeaders - .TryAddWithoutValidation("cookie", "cf_clearance=Gg3bVffg9fOL_.9fIdKmu5PJS86eTI.yTrhbR8z2tPc-1652310659-0-250"); - - http.DefaultRequestHeaders - .TryAddWithoutValidation("user-agent", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.60 Safari/537.36"); - var images = await http.GetFromJsonAsync>(uri, _serializerOptions, cancel); - - if (images is null) - return new(); - - return images.Where(img => !string.IsNullOrWhiteSpace(img.Image)).ToList(); - } -} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Nsfw/_Common/Downloaders/SafebooruImageDownloader.cs b/src/NadekoBot/Modules/Nsfw/_Common/Downloaders/SafebooruImageDownloader.cs deleted file mode 100644 index 86e4d2a88..000000000 --- a/src/NadekoBot/Modules/Nsfw/_Common/Downloaders/SafebooruImageDownloader.cs +++ /dev/null @@ -1,30 +0,0 @@ -#nullable disable -using System.Net.Http.Json; - -namespace NadekoBot.Modules.Nsfw.Common; - -public class SafebooruImageDownloader : ImageDownloader -{ - public SafebooruImageDownloader(IHttpClientFactory http) - : base(Booru.Safebooru, http) - { - } - - public override async Task> DownloadImagesAsync( - string[] tags, - int page, - bool isExplicit = false, - CancellationToken cancel = default) - { - var tagString = ImageDownloaderHelper.GetTagString(tags); - var uri = - $"https://safebooru.org/index.php?page=dapi&s=post&q=index&limit=200&tags={tagString}&json=1&pid={page}"; - - using var http = _http.CreateClient(); - var images = await http.GetFromJsonAsync>(uri, _serializerOptions, cancel); - if (images is null) - return new(); - - return images; - } -} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Nsfw/_Common/Downloaders/SankakuImageDownloader.cs b/src/NadekoBot/Modules/Nsfw/_Common/Downloaders/SankakuImageDownloader.cs deleted file mode 100644 index cba25f452..000000000 --- a/src/NadekoBot/Modules/Nsfw/_Common/Downloaders/SankakuImageDownloader.cs +++ /dev/null @@ -1,35 +0,0 @@ -#nullable disable -using System.Text.Json; -using Nadeko.Common; - -namespace NadekoBot.Modules.Nsfw.Common; - -public sealed class SankakuImageDownloader : ImageDownloader -{ - private readonly string _baseUrl; - - public SankakuImageDownloader(IHttpClientFactory http) - : base(Booru.Sankaku, http) - { - _baseUrl = "https://capi-v2.sankakucomplex.com"; - } - - public override async Task> DownloadImagesAsync( - string[] tags, - int page, - bool isExplicit = false, - CancellationToken cancel = default) - { - // explicit probably not supported - var tagString = ImageDownloaderHelper.GetTagString(tags); - - var uri = $"{_baseUrl}/posts?tags={tagString}&limit=50"; - - using var http = _http.CreateClient(); - http.AddFakeHeaders(); - var data = await http.GetStringAsync(uri, cancel); - return JsonSerializer.Deserialize(data, _serializerOptions) - ?.Where(x => !string.IsNullOrWhiteSpace(x.FileUrl) && x.FileType.StartsWith("image")) - .ToList(); - } -} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Nsfw/_Common/Downloaders/YandereImageDownloader.cs b/src/NadekoBot/Modules/Nsfw/_Common/Downloaders/YandereImageDownloader.cs deleted file mode 100644 index 8141230b1..000000000 --- a/src/NadekoBot/Modules/Nsfw/_Common/Downloaders/YandereImageDownloader.cs +++ /dev/null @@ -1,30 +0,0 @@ -#nullable disable -using System.Net.Http.Json; - -namespace NadekoBot.Modules.Nsfw.Common; - -public sealed class YandereImageDownloader : ImageDownloader -{ - private readonly string _baseUrl; - - public YandereImageDownloader(IHttpClientFactory http) - : base(Booru.Yandere, http) - => _baseUrl = "https://yande.re"; - - public override async Task> DownloadImagesAsync( - string[] tags, - int page, - bool isExplicit = false, - CancellationToken cancel = default) - { - var tagString = ImageDownloaderHelper.GetTagString(tags, isExplicit); - - var uri = $"{_baseUrl}/post.json?limit=200&tags={tagString}&page={page}"; - - using var http = _http.CreateClient(); - var imageObjects = await http.GetFromJsonAsync(uri, _serializerOptions, cancel); - if (imageObjects is null) - return new(); - return imageObjects.Where(x => x.FileUrl is not null).ToList(); - } -} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Nsfw/_Common/E621Object.cs b/src/NadekoBot/Modules/Nsfw/_Common/E621Object.cs deleted file mode 100644 index c6220cbed..000000000 --- a/src/NadekoBot/Modules/Nsfw/_Common/E621Object.cs +++ /dev/null @@ -1,27 +0,0 @@ -#nullable disable -namespace NadekoBot.Modules.Nsfw.Common; - -public class E621Object : IImageData -{ - public FileData File { get; set; } - public TagData Tags { get; set; } - public ScoreData Score { get; set; } - - public ImageData ToCachedImageData(Booru type) - => new(File.Url, Booru.E621, Tags.General, Score.Total.ToString()); - - public class FileData - { - public string Url { get; set; } - } - - public class TagData - { - public string[] General { get; set; } - } - - public class ScoreData - { - public int Total { get; set; } - } -} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Nsfw/_Common/IImageData.cs b/src/NadekoBot/Modules/Nsfw/_Common/IImageData.cs deleted file mode 100644 index 12414c85d..000000000 --- a/src/NadekoBot/Modules/Nsfw/_Common/IImageData.cs +++ /dev/null @@ -1,7 +0,0 @@ -#nullable disable -namespace NadekoBot.Modules.Nsfw.Common; - -public interface IImageData -{ - ImageData ToCachedImageData(Booru type); -} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Nsfw/_Common/ImageData.cs b/src/NadekoBot/Modules/Nsfw/_Common/ImageData.cs deleted file mode 100644 index ddc64c5c0..000000000 --- a/src/NadekoBot/Modules/Nsfw/_Common/ImageData.cs +++ /dev/null @@ -1,39 +0,0 @@ -#nullable disable -namespace NadekoBot.Modules.Nsfw.Common; - -public class ImageData : IComparable -{ - public Booru SearchType { get; } - public string FileUrl { get; } - public HashSet Tags { get; } - public string Rating { get; } - - public ImageData( - string url, - Booru type, - string[] tags, - string rating) - { - if (type == Booru.Danbooru && !Uri.IsWellFormedUriString(url, UriKind.Absolute)) - FileUrl = "https://danbooru.donmai.us" + url; - else - FileUrl = url.StartsWith("http", StringComparison.InvariantCulture) ? url : "https:" + url; - - SearchType = type; - FileUrl = url; - Tags = tags.ToHashSet(); - Rating = rating; - } - - public override string ToString() - => FileUrl; - - public override int GetHashCode() - => FileUrl.GetHashCode(); - - public override bool Equals(object obj) - => obj is ImageData ico && ico.FileUrl == FileUrl; - - public int CompareTo(ImageData other) - => string.Compare(FileUrl, other.FileUrl, StringComparison.InvariantCulture); -} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Nsfw/_Common/Rule34Object.cs b/src/NadekoBot/Modules/Nsfw/_Common/Rule34Object.cs deleted file mode 100644 index ea1d841a7..000000000 --- a/src/NadekoBot/Modules/Nsfw/_Common/Rule34Object.cs +++ /dev/null @@ -1,17 +0,0 @@ -#nullable disable -using System.Text.Json.Serialization; - -namespace NadekoBot.Modules.Nsfw.Common; - -public class Rule34Object : IImageData -{ - public string Image { get; init; } - public int Directory { get; init; } - public string Tags { get; init; } - public int Score { get; init; } - [JsonPropertyName("file_url")] - public string FileUrl { get; init; } - - public ImageData ToCachedImageData(Booru type) - => new(FileUrl, Booru.Rule34, Tags.Split(' '), Score.ToString()); -} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Nsfw/_Common/SafebooruElement.cs b/src/NadekoBot/Modules/Nsfw/_Common/SafebooruElement.cs deleted file mode 100644 index 4ae83d1fc..000000000 --- a/src/NadekoBot/Modules/Nsfw/_Common/SafebooruElement.cs +++ /dev/null @@ -1,18 +0,0 @@ -#nullable disable -namespace NadekoBot.Modules.Nsfw.Common; - -public class SafebooruElement : IImageData -{ - public string Directory { get; set; } - public string Image { get; set; } - - - public string FileUrl - => $"https://safebooru.org/images/{Directory}/{Image}"; - - public string Rating { get; set; } - public string Tags { get; set; } - - public ImageData ToCachedImageData(Booru type) - => new(FileUrl, Booru.Safebooru, Tags.Split(' '), Rating); -} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Nsfw/_Common/SankakuImageObject.cs b/src/NadekoBot/Modules/Nsfw/_Common/SankakuImageObject.cs deleted file mode 100644 index d5d5949dd..000000000 --- a/src/NadekoBot/Modules/Nsfw/_Common/SankakuImageObject.cs +++ /dev/null @@ -1,26 +0,0 @@ -#nullable disable -using System.Text.Json.Serialization; - -namespace NadekoBot.Modules.Nsfw.Common; - -public class SankakuImageObject : IImageData -{ - [JsonPropertyName("file_url")] - public string FileUrl { get; set; } - - [JsonPropertyName("file_type")] - public string FileType { get; set; } - - public Tag[] Tags { get; set; } - - [JsonPropertyName("total_score")] - public int Score { get; set; } - - public ImageData ToCachedImageData(Booru type) - => new(FileUrl, Booru.Sankaku, Tags.Select(x => x.Name).ToArray(), Score.ToString()); - - public class Tag - { - public string Name { get; set; } - } -} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Searches/_Common/ImageCacherObject.cs b/src/NadekoBot/Modules/Searches/_Common/ImageCacherObject.cs deleted file mode 100644 index d3ed39995..000000000 --- a/src/NadekoBot/Modules/Searches/_Common/ImageCacherObject.cs +++ /dev/null @@ -1,46 +0,0 @@ -#nullable disable -using NadekoBot.Modules.Nsfw.Common; - -namespace NadekoBot.Modules.Searches.Common; - -public class ImageCacherObject : IComparable -{ - public Booru SearchType { get; } - public string FileUrl { get; } - public HashSet Tags { get; } - public string Rating { get; } - - public ImageCacherObject(DapiImageObject obj, Booru type) - { - if (type == Booru.Danbooru && !Uri.IsWellFormedUriString(obj.FileUrl, UriKind.Absolute)) - FileUrl = "https://danbooru.donmai.us" + obj.FileUrl; - else - { - FileUrl = obj.FileUrl.StartsWith("http", StringComparison.InvariantCulture) - ? obj.FileUrl - : "https:" + obj.FileUrl; - } - - SearchType = type; - Rating = obj.Rating; - Tags = new((obj.Tags ?? obj.TagString).Split(' ')); - } - - public ImageCacherObject( - string url, - Booru type, - string tags, - string rating) - { - SearchType = type; - FileUrl = url; - Tags = new(tags.Split(' ')); - Rating = rating; - } - - public override string ToString() - => FileUrl; - - public int CompareTo(ImageCacherObject other) - => string.Compare(FileUrl, other.FileUrl, StringComparison.InvariantCulture); -} \ No newline at end of file diff --git a/src/NadekoBot/NadekoBot.csproj b/src/NadekoBot/NadekoBot.csproj index 93b167a36..78e69db50 100644 --- a/src/NadekoBot/NadekoBot.csproj +++ b/src/NadekoBot/NadekoBot.csproj @@ -97,10 +97,6 @@ - - - - @@ -130,6 +126,18 @@ Always + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + diff --git a/src/NadekoBot/_Extensions/ServiceCollectionExtensions.cs b/src/NadekoBot/_Extensions/ServiceCollectionExtensions.cs index f0d2e3551..84c1bccfd 100644 --- a/src/NadekoBot/_Extensions/ServiceCollectionExtensions.cs +++ b/src/NadekoBot/_Extensions/ServiceCollectionExtensions.cs @@ -130,21 +130,24 @@ public static class ServiceCollectionExtensions public static IKernel AddLifetimeServices(this IKernel kernel) { - Assembly.GetExecutingAssembly() - .ExportedTypes - .Where(x => x.IsPublic && x.IsClass && !x.IsAbstract) + kernel.Bind(scan => + { + scan.FromThisAssembly() + .SelectAllClasses() .Where(c => (c.IsAssignableTo(typeof(INService)) || c.IsAssignableTo(typeof(IExecOnMessage)) || c.IsAssignableTo(typeof(IInputTransformer)) || c.IsAssignableTo(typeof(IExecPreCommand)) || c.IsAssignableTo(typeof(IExecPostCommand)) || c.IsAssignableTo(typeof(IExecNoCommand))) - && !c.HasAttribute() -#if GLOBAL_NADEKO - && !c.HasAttribute() + && !c.HasAttribute() +#if GLOBAL_NADEK + && !c.HasAttribute() #endif - ); - + ) + .BindToSelfWithInterfaces() + .Configure(c => c.InSingletonScope()); + }); return kernel; } diff --git a/src/NadekoBot/libopus.so b/src/NadekoBot/data/lib/libopus.so similarity index 100% rename from src/NadekoBot/libopus.so rename to src/NadekoBot/data/lib/libopus.so diff --git a/src/NadekoBot/libsodium.dll b/src/NadekoBot/data/lib/libsodium.dll similarity index 100% rename from src/NadekoBot/libsodium.dll rename to src/NadekoBot/data/lib/libsodium.dll diff --git a/src/NadekoBot/libsodium.so b/src/NadekoBot/data/lib/libsodium.so similarity index 100% rename from src/NadekoBot/libsodium.so rename to src/NadekoBot/data/lib/libsodium.so diff --git a/src/NadekoBot/opus.dll b/src/NadekoBot/data/lib/opus.dll similarity index 100% rename from src/NadekoBot/opus.dll rename to src/NadekoBot/data/lib/opus.dll