├── .gitattributes ├── .gitignore ├── .gitmodules ├── Daylily.sln ├── LICENSE ├── README.md ├── daylily.sln.DotSettings └── daylily ├── App.xaml ├── App.xaml.cs ├── Configs.cs ├── Migrations ├── 20220316084525_initial.Designer.cs ├── 20220316084525_initial.cs └── OsuDbContextModelSnapshot.cs ├── MyCommandLineAnalyzer.cs ├── NLog.config ├── NLog.debug.config ├── Plugins ├── Basic │ ├── CheckAt.cs │ ├── CsxPlugin.cs │ ├── DragonLanguage.cs │ ├── Echo.cs │ ├── HelpPlugin │ │ ├── Help.cs │ │ ├── HelpDetailControl.xaml │ │ ├── HelpDetailControl.xaml.cs │ │ ├── HelpDetailVm.cs │ │ ├── HelpListControl.xaml │ │ ├── HelpListControl.xaml.cs │ │ ├── HelpListVm.cs │ │ ├── PluginDetailVm.cs │ │ ├── PluginInfoVm.cs │ │ ├── ScopeInfoVm.cs │ │ ├── String2DescriptionConverter.cs │ │ ├── String2LowerSnakeConverter.cs │ │ └── ZeroToCollapsedConverter.cs │ ├── KeywordTrigger.cs │ ├── Konachan.cs │ ├── PeroControl.xaml │ ├── PeroControl.xaml.cs │ ├── Roll.cs │ ├── RpsDice.cs │ ├── Smoke.cs │ ├── Tuling.cs │ ├── WashingMachine.cs │ └── WhatToEat.cs ├── Core │ ├── CliPrint.cs │ ├── CommandRate.cs │ ├── GuiManaging │ │ ├── GuiManager.cs │ │ ├── ManagerWindow.xaml │ │ └── ManagerWindow.xaml.cs │ ├── GuiMessage │ │ ├── GuiMessageSend.cs │ │ ├── GuiMessageWindow.xaml │ │ └── GuiMessageWindow.xaml.cs │ ├── MessageLogging.cs │ ├── PluginFilter.cs │ ├── PowerOff.cs │ ├── PowerOffFilterService.cs │ ├── Reboot.cs │ └── SendMessage.cs ├── Osu │ ├── ApiService.cs │ ├── AuthenticationController.cs │ ├── BeatmapStats │ │ ├── BeatmapStatistics.cs │ │ ├── BeatmapStatsControl.xaml │ │ ├── BeatmapStatsControl.xaml.cs │ │ ├── BeatmapStatsVm.cs │ │ ├── DateModel.cs │ │ ├── FavoriteComparer.cs │ │ ├── PlayCountComparer.cs │ │ └── TickComparer.cs │ ├── Data │ │ ├── BeatmapScan.cs │ │ ├── BeatmapStat.cs │ │ ├── BeatmapSubscribe.cs │ │ ├── OsuDbContext.cs │ │ ├── OsuToken.cs │ │ └── OsuUserInfo.cs │ ├── Me │ │ ├── MeControl.xaml │ │ └── MeControl.xaml.cs │ ├── MePlugin.cs │ ├── OsuTokenReceivedEvent.cs │ ├── Qqm.cs │ ├── RecentPlayPlugin.cs │ ├── SearchBnPlugins │ │ ├── AllUsersByMode.cs │ │ ├── RelevantInfo.cs │ │ ├── SearchBn.cs │ │ ├── SearchBnControl.xaml │ │ ├── SearchBnControl.xaml.cs │ │ └── SearchBnVm.cs │ ├── SetId.cs │ └── UserPage │ │ ├── UserPageControl.xaml │ │ ├── UserPageControl.xaml.cs │ │ ├── UserPagePlugin.cs │ │ ├── UserPageVm.cs │ │ └── WebPrintScreen.cs └── Services │ ├── CacheManagerService.cs │ ├── CliPrintMe.cs │ ├── FailBindingReplyService.cs │ ├── FailExecuteReplyService.cs │ ├── MemoryCheckService.cs │ ├── MessageAvoidRepeatService.cs │ └── SensitiveMatchService.cs ├── Program.cs ├── Resources └── Fonts │ ├── SourceHanSerifCn.ttf │ ├── SourceSansPro-Black.ttf │ ├── SourceSansPro-Bold.ttf │ ├── SourceSansPro-ExtraLight.ttf │ ├── SourceSansPro-Light.ttf │ ├── SourceSansPro-Regular.ttf │ └── SourceSansPro-Semibold.ttf ├── ThirdParty ├── Moebooru │ ├── Api.cs │ └── Post.cs ├── TinyPinyin.Core.Standard │ ├── Data │ │ ├── PinyinCode1.cs │ │ ├── PinyinCode2.cs │ │ ├── PinyinCode3.cs │ │ └── PinyinData.cs │ ├── Engine.cs │ ├── IPinyinDict.cs │ ├── PinyinHelper.cs │ ├── PinyinMapDict.cs │ ├── SegmentationSelector.cs │ └── readme.txt ├── ToolGood.Words │ ├── BaseSearchEx2.cs │ ├── StringSearchEx3.cs │ ├── TrieNode.cs │ ├── TrieNodeEx.cs │ └── readme.txt └── Tuling │ ├── RequestModel │ ├── InputImage.cs │ ├── InputMedia.cs │ ├── InputText.cs │ ├── Location.cs │ ├── Perception.cs │ ├── Request.cs │ ├── RequestType.cs │ ├── SelfInfo.cs │ └── UserInfo.cs │ ├── ResponseModel │ ├── Intent.cs │ ├── Parameters.cs │ ├── RequestType.cs │ ├── Response.cs │ ├── Result.cs │ └── Values.cs │ └── TulingClient.cs ├── Utils ├── EncryptUtil.cs ├── ExceptionExtensions.cs └── StringUtil.cs ├── app.manifest ├── appsettings.yaml └── daylily.csproj /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "depencencies/MilkiBotFramework"] 2 | path = depencencies/MilkiBotFramework 3 | url = https://github.com/Milkitic/MilkiBotFramework.git 4 | -------------------------------------------------------------------------------- /Daylily.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.0.32126.317 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "daylily", "daylily\daylily.csproj", "{DB9E989D-D1E8-49B8-861C-93294AA62758}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "dependencies", "dependencies", "{CAD00200-1E33-4ECF-BDB0-E4C44BAFD280}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MilkiBotFramework.Aspnetcore", "depencencies\MilkiBotFramework\src\MilkiBotFramework.Aspnetcore\MilkiBotFramework.Aspnetcore.csproj", "{5B90A1C7-04E1-428D-9212-2A26124CE6E6}" 11 | EndProject 12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MilkiBotFramework", "depencencies\MilkiBotFramework\src\MilkiBotFramework\MilkiBotFramework.csproj", "{5732688A-40D5-4FD1-812D-09242527E059}" 13 | EndProject 14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MilkiBotFramework.Imaging.Wpf", "depencencies\MilkiBotFramework\src\MilkiBotFramework.Imaging.Wpf\MilkiBotFramework.Imaging.Wpf.csproj", "{805400BF-AB0C-4D4F-925A-456A3680FC45}" 15 | EndProject 16 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MilkiBotFramework.Platforms.GoCqHttp", "depencencies\MilkiBotFramework\src\Platforms\MilkiBotFramework.Platforms.GoCqHttp\MilkiBotFramework.Platforms.GoCqHttp.csproj", "{B35D87B8-FA4F-438C-A5D7-20CBDF8E5F78}" 17 | EndProject 18 | Global 19 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 20 | Debug|Any CPU = Debug|Any CPU 21 | Release|Any CPU = Release|Any CPU 22 | EndGlobalSection 23 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 24 | {DB9E989D-D1E8-49B8-861C-93294AA62758}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 25 | {DB9E989D-D1E8-49B8-861C-93294AA62758}.Debug|Any CPU.Build.0 = Debug|Any CPU 26 | {DB9E989D-D1E8-49B8-861C-93294AA62758}.Release|Any CPU.ActiveCfg = Release|Any CPU 27 | {DB9E989D-D1E8-49B8-861C-93294AA62758}.Release|Any CPU.Build.0 = Release|Any CPU 28 | {5B90A1C7-04E1-428D-9212-2A26124CE6E6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 29 | {5B90A1C7-04E1-428D-9212-2A26124CE6E6}.Debug|Any CPU.Build.0 = Debug|Any CPU 30 | {5B90A1C7-04E1-428D-9212-2A26124CE6E6}.Release|Any CPU.ActiveCfg = Release|Any CPU 31 | {5B90A1C7-04E1-428D-9212-2A26124CE6E6}.Release|Any CPU.Build.0 = Release|Any CPU 32 | {5732688A-40D5-4FD1-812D-09242527E059}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 33 | {5732688A-40D5-4FD1-812D-09242527E059}.Debug|Any CPU.Build.0 = Debug|Any CPU 34 | {5732688A-40D5-4FD1-812D-09242527E059}.Release|Any CPU.ActiveCfg = Release|Any CPU 35 | {5732688A-40D5-4FD1-812D-09242527E059}.Release|Any CPU.Build.0 = Release|Any CPU 36 | {805400BF-AB0C-4D4F-925A-456A3680FC45}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 37 | {805400BF-AB0C-4D4F-925A-456A3680FC45}.Debug|Any CPU.Build.0 = Debug|Any CPU 38 | {805400BF-AB0C-4D4F-925A-456A3680FC45}.Release|Any CPU.ActiveCfg = Release|Any CPU 39 | {805400BF-AB0C-4D4F-925A-456A3680FC45}.Release|Any CPU.Build.0 = Release|Any CPU 40 | {B35D87B8-FA4F-438C-A5D7-20CBDF8E5F78}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 41 | {B35D87B8-FA4F-438C-A5D7-20CBDF8E5F78}.Debug|Any CPU.Build.0 = Debug|Any CPU 42 | {B35D87B8-FA4F-438C-A5D7-20CBDF8E5F78}.Release|Any CPU.ActiveCfg = Release|Any CPU 43 | {B35D87B8-FA4F-438C-A5D7-20CBDF8E5F78}.Release|Any CPU.Build.0 = Release|Any CPU 44 | EndGlobalSection 45 | GlobalSection(SolutionProperties) = preSolution 46 | HideSolutionNode = FALSE 47 | EndGlobalSection 48 | GlobalSection(NestedProjects) = preSolution 49 | {5B90A1C7-04E1-428D-9212-2A26124CE6E6} = {CAD00200-1E33-4ECF-BDB0-E4C44BAFD280} 50 | {5732688A-40D5-4FD1-812D-09242527E059} = {CAD00200-1E33-4ECF-BDB0-E4C44BAFD280} 51 | {805400BF-AB0C-4D4F-925A-456A3680FC45} = {CAD00200-1E33-4ECF-BDB0-E4C44BAFD280} 52 | {B35D87B8-FA4F-438C-A5D7-20CBDF8E5F78} = {CAD00200-1E33-4ECF-BDB0-E4C44BAFD280} 53 | EndGlobalSection 54 | GlobalSection(ExtensibilityGlobals) = postSolution 55 | SolutionGuid = {A6BCFAD8-B150-476D-A331-F6289BBF956B} 56 | EndGlobalSection 57 | EndGlobal 58 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Milkitic 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # daylily 2 | 我叫黄花菜w,是基于[MilkiBotFramework](https://github.com/Milkitic/MilkiBotFramework)的机器人。 3 | 这是我的开源仓库,包含了大部分的可开源的逻辑。 4 | > 请注意,实际运营的我包含着一些非公开插件。 5 | 6 | 本项目亦可作为MilkiBotFramework示例仓库,这将教你如何优雅地使用该框架编写机器人。 7 | 8 | ## 指引 9 | 不同插件使用了MilkiBotFramework的框架的不同处理方法,请根据实际需求参考。 10 | 11 | ### 基础互动插件 12 | * 【@检测】`CheckCqAt`:解析富文本、发送富文本,获取机器人账号信息 13 | * 【缩写查询】`CsxPlugin`:命令处理、调用HTTP请求 14 | * 【龙语识别】`DragonLanguage`:复杂逻辑相关 15 | * 【Ping-pong】`Echo` 16 | * 【关键词触发】`KeywordTrigger` 17 | * 【konachan】`Konachan` 18 | * 【获取随机数】`Roll` 19 | * 【自助禁言】`Smoke`:使用专用API 20 | * 【图灵】`Tuling` 21 | * 【洗衣机插件】`WashingMachine`:图片处理示例(包括gif)、上下文对话 22 | * 【今天吃什么】`WhatToEat`:托管配置处理,获取Bot配置文件 23 | * 【Bot帮助】`Help`:使用UI框架绘图,获取所有插件信息 24 | 25 | ### osu!插件 26 | * `AuthenticationController`:ASP.NET Core Web API的控制器声明 27 | * `OsuDbContext`:托管的数据库上下文声明 28 | * `ApiService` 29 | * 【绑定osu!账号】`SetId`:与Controller的互动、EventBus的使用、插件之间注入 30 | * 【成绩查询】`RecentPlayPlugin`:参数级权限声明 31 | * 【个人名片】`MePlugin`:使用托管的数据库 32 | * 【个人介绍页面】`UserPagePlugin` 33 | * 【BN信息搜索】`SearchBn` 34 | * 【地图数据订阅】`BeatmapStatistics` 35 | 36 | ### 基础处理/控制插件 37 | * 【控制台消息输出】`CliPrint` 38 | * 【命令热度分析】`CommandRate` 39 | * 【聊天记录(非持久化)】`MessageLogging` 40 | * 【插件管理】`PluginFilter`:控制插件行为、获取用户输入解析结果 41 | * 【睡眠】`PowerOff`:任务计划程序、原生MessageApi 42 | * 【睡眠控制消息输出】`PowerOffFilterService`:`ServicePlugin`的`BeforeSend`的使用 43 | * 【远程重启】`Reboot`:任务计划程序、原生MessageApi 44 | * 【发送自定义消息】`SendMessage`:限制命令的权限、群私聊 45 | 46 | ### 服务插件 47 | * 【缓存定时清理】`CacheManagerService` 48 | * 【控制台消息输出(Bot)】`CliPrintMe` 49 | * `FailBindingReplyService`:`ServicePlugin`的`OnBindingFailed`的使用 50 | * `FailExecuteReplyService`:`ServicePlugin`的`OnPluginException`的使用 51 | * 【内存溢出检测】`MemoryCheckService` 52 | * 【发言重复过滤】`MessageAvoidRepeatService` 53 | * 【敏感词屏蔽】`SensitiveMatchService` 54 | 55 | ## 许可声明 56 | 本项目代码部分采用MIT许可。 57 | 58 | 其中包含的Resources/Fonts的字体文件为 Google 的 Source Sans Pro,其采用 [Open Font License](https://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL)。 -------------------------------------------------------------------------------- /daylily.sln.DotSettings: -------------------------------------------------------------------------------- 1 |  2 | True -------------------------------------------------------------------------------- /daylily/App.xaml: -------------------------------------------------------------------------------- 1 |  6 | 7 | pack://application:,,,/daylily;component/Resources/Fonts/#Source Sans Pro ExtraLight,pack://application:,,,/daylily;component/Resources/Fonts/#思源屏显臻宋 CN 8 | pack://application:,,,/daylily;component/Resources/Fonts/#Source Sans Pro Light,pack://application:,,,/daylily;component/Resources/Fonts/#思源屏显臻宋 CN 9 | pack://application:,,,/daylily;component/Resources/Fonts/#Source Sans Pro,pack://application:,,,/daylily;component/Resources/Fonts/#思源屏显臻宋 CN 10 | pack://application:,,,/daylily;component/Resources/Fonts/#Source Sans Pro Semibold,pack://application:,,,/daylily;component/Resources/Fonts/#思源屏显臻宋 CN 11 | pack://application:,,,/daylily;component/Resources/Fonts/#Source Sans Pro Black,pack://application:,,,/daylily;component/Resources/Fonts/#思源屏显臻宋 CN 12 | 13 | 14 | -------------------------------------------------------------------------------- /daylily/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | 3 | namespace daylily; 4 | 5 | public partial class App : Application 6 | { 7 | } -------------------------------------------------------------------------------- /daylily/Configs.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Concurrent; 2 | using System.ComponentModel; 3 | using MilkiBotFramework.Messaging; 4 | using MilkiBotFramework.Plugining.Configuration; 5 | using MilkiBotFramework.Utils; 6 | using YamlDotNet.Serialization; 7 | 8 | // ReSharper disable once CheckNamespace 9 | namespace daylily; 10 | 11 | public sealed class PluginManagerConfig : ConfigurationBase 12 | { 13 | [Description("插件禁用列表")] 14 | [YamlMember(Alias = "DisabledList")] 15 | public ConcurrentDictionary> IdentityDisabledDictionary { get; set; } = new(); 16 | } 17 | 18 | public sealed class TulingConfig : ConfigurationBase 19 | { 20 | public ConcurrentDictionary? ApiInfos { get; set; } = new(); 21 | } 22 | 23 | public sealed class OsuConfig : ConfigurationBase 24 | { 25 | public string QQAesKey { get; set; } = "aeskey"; 26 | public string QQAesIV { get; set; } = "aesiv"; 27 | public int ClientId { get; set; } = 114514; 28 | public string ClientSecret { get; set; } = "ClientSecret"; 29 | public string ServerRedirectUri { get; set; } = "ServerRedirectUri"; 30 | public int ServerRedirectPort { get; set; } = 23333; 31 | 32 | } 33 | 34 | public class KeywordTriggerConfig : ConfigurationBase 35 | { 36 | public class TriggerObject 37 | { 38 | public TriggerObject() 39 | { 40 | } 41 | 42 | public TriggerObject(List words, List pictures, double chancePercent) 43 | { 44 | Words = words; 45 | Pictures = pictures; 46 | ChancePercent = chancePercent; 47 | } 48 | 49 | public List Words { get; set; } 50 | public List Pictures { get; set; } 51 | public double ChancePercent { get; set; } 52 | } 53 | 54 | public List UserDictionary { get; set; } = new List 55 | { 56 | new(new List { "我" }, 57 | new List 58 | { 59 | "me1.jpg" 60 | }, 0.5), 61 | new(new List { "你" }, 62 | new List 63 | { 64 | "you1.jpg", "you2.jpg" 65 | }, 2), 66 | new(new List { "为啥", "为什么", "为毛", "为嘛", "why " }, 67 | new List 68 | { 69 | "why1.jpg" 70 | }, 20), 71 | new(new List { "看来", "原来" }, 72 | new List 73 | { 74 | "kanlai1.jpg", "kanlai2.jpg" 75 | }, 30), 76 | new(new List { "黄花菜" }, 77 | new List 78 | { 79 | "sb1.jpg", "sb2.jpg", "sb3.jpg", "sb4.jpg", "sb5.jpg", "sb6.jpg", "sb7.jpg", "sb8.jpg", 80 | "sb9.jpg" 81 | }, 50) 82 | }; 83 | } 84 | 85 | public sealed class CommandRateConfig : ConfigurationBase 86 | { 87 | public ConcurrentDictionary CommandRate { get; set; } = new(); 88 | } 89 | 90 | public sealed class DragonLanguageConfig : ConfigurationBase 91 | { 92 | public class UserExpression 93 | { 94 | public int Times { get; set; } = 1; 95 | public string Expression { get; set; } 96 | } 97 | 98 | public ConcurrentDictionary>? UserDictionary { get; set; } = new(); 99 | } 100 | 101 | public sealed class ShuntDownConfig : ConfigurationBase 102 | { 103 | [YamlIgnore] 104 | internal readonly AsyncLock AsyncLock = new(); 105 | public ConcurrentDictionary? ExpireTimeDictionary { get; set; } = new(); 106 | } 107 | 108 | public sealed class WhatToEatConfig : ConfigurationBase 109 | { 110 | public class GroupMeals 111 | { 112 | [YamlIgnore] 113 | public readonly ReaderWriterLockSlim CollectionLock = new(); 114 | 115 | [YamlIgnore] 116 | public DateTime Cooldown { get; set; } = DateTime.MinValue; 117 | [YamlIgnore] 118 | public Dictionary> UserCoolDownList { get; set; } = new(); 119 | public bool IsSubChannelOnly { get; set; } 120 | public List Meals { get; set; } = new(); 121 | } 122 | 123 | public ConcurrentDictionary Sessions { get; set; } = new(); 124 | } -------------------------------------------------------------------------------- /daylily/MyCommandLineAnalyzer.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.CodeAnalysis; 2 | using MilkiBotFramework; 3 | using MilkiBotFramework.Plugining.CommandLine; 4 | 5 | namespace daylily; 6 | 7 | public class MyCommandLineAnalyzer : CommandLineAnalyzer 8 | { 9 | public MyCommandLineAnalyzer(BotOptions botOptions) : base(botOptions) 10 | { 11 | } 12 | 13 | public override bool TryAnalyze(string input, 14 | [NotNullWhen(true)] out CommandLineResult? result, 15 | out CommandLineException? exception) 16 | { 17 | var source = input.AsSpan().Trim(); 18 | if (source.Equals("帮助", StringComparison.InvariantCulture)) 19 | { 20 | input = $"{GetCommandFlag()}help"; 21 | } 22 | else if (source.Contains("吃啥", StringComparison.InvariantCulture) || 23 | source.Contains("吃什么", StringComparison.InvariantCulture)) 24 | { 25 | input = $"{GetCommandFlag()}what2eat"; 26 | } 27 | else if (source.Equals("摆酒席", StringComparison.InvariantCulture)) 28 | { 29 | input = $"{GetCommandFlag()}what2eat10"; 30 | } 31 | 32 | return base.TryAnalyze(input, out result, out exception); 33 | } 34 | } -------------------------------------------------------------------------------- /daylily/NLog.config: -------------------------------------------------------------------------------- 1 |  2 | 4 | 5 | 6 | 7 | 8 | 11 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /daylily/NLog.debug.config: -------------------------------------------------------------------------------- 1 |  2 | 4 | 5 | 6 | 7 | 8 | 11 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /daylily/Plugins/Basic/CheckAt.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.IO; 3 | using MilkiBotFramework.ContactsManaging; 4 | using MilkiBotFramework.Messaging; 5 | using MilkiBotFramework.Messaging.RichMessages; 6 | using MilkiBotFramework.Plugining; 7 | using MilkiBotFramework.Plugining.Attributes; 8 | 9 | namespace daylily.Plugins.Basic; 10 | 11 | [PluginIdentifier("e6d765b3-a015-4192-9cc1-0cfa5c13ec55", "@检测")] 12 | [PluginLifetime(PluginLifetime.Scoped)] 13 | [Description("当自己被at时回击at对方")] 14 | public class CheckAt : BasicPlugin 15 | { 16 | private readonly IContactsManager _contactsManager; 17 | 18 | public CheckAt(IContactsManager contactsManager) 19 | { 20 | _contactsManager = contactsManager; 21 | } 22 | 23 | public override async IAsyncEnumerable OnMessageReceived(MessageContext context) 24 | { 25 | if (context.MessageIdentity?.MessageType != MessageType.Channel) yield break; 26 | var richMsg = context.GetRichMessage(); 27 | var allAts = richMsg 28 | .Where(k => k is At) 29 | .Select(k => ((At)k).UserId) 30 | .ToHashSet(); 31 | var result = await _contactsManager.TryGetOrUpdateSelfInfo(); 32 | if (!result.IsSuccess) yield break; 33 | if (!allAts.Contains(result.SelfInfo!.UserId) && !allAts.Contains("-1")) yield break; 34 | 35 | await Task.Delay(Random.Shared.Next(5000)); 36 | if (Random.Shared.NextDouble() < 0.9) 37 | { 38 | yield return Reply(new At(context.MessageUserIdentity!.UserId), false); 39 | } 40 | else 41 | { 42 | var imagePath = Path.Combine(PluginHome, "pandas", "at.jpg"); 43 | yield return Reply(new FileImage(imagePath), false); 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /daylily/Plugins/Basic/CsxPlugin.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.Text; 3 | using System.Text.Json.Serialization; 4 | using System.Text.RegularExpressions; 5 | using MilkiBotFramework.Connecting; 6 | using MilkiBotFramework.Messaging; 7 | using MilkiBotFramework.Plugining; 8 | using MilkiBotFramework.Plugining.Attributes; 9 | 10 | namespace daylily.Plugins.Basic; 11 | 12 | [PluginIdentifier("77dabbaa-1f4a-49f0-9813-b6071936e7f6", "缩写查询")] 13 | [Description("缩写查询 (https://github.com/itorr/nbnhhsh)")] 14 | public class CsxPlugin : BasicPlugin 15 | { 16 | private readonly LightHttpClient _lightHttpClient; 17 | 18 | public CsxPlugin(LightHttpClient lightHttpClient) 19 | { 20 | _lightHttpClient = lightHttpClient; 21 | } 22 | 23 | private static readonly Regex Regex = new("[A-za-z0-9]+"); 24 | 25 | [CommandHandler("csx")] 26 | public async Task Guess( 27 | [Argument, Description("缩写词或段落")] string? text = null) 28 | { 29 | if (string.IsNullOrWhiteSpace(text)) 30 | return Reply("请提供关键词"); 31 | 32 | var matches = Regex.Matches(text).Where(k => k.Success).ToArray(); 33 | if (matches.Length == 0) 34 | return Reply("未检测到关键词"); 35 | 36 | var enumerable = matches 37 | .SelectMany(k => k.Groups.Values 38 | .Where(o => o.Length > 1) 39 | .Select(o => o.Value)) 40 | .Distinct() 41 | .ToList(); 42 | 43 | if (enumerable.Count > 8) 44 | { 45 | return Reply("为防止刷屏,关键词不得同时超过8个"); 46 | } 47 | 48 | text = string.Join(",", enumerable).ToLower(); 49 | var result = await _lightHttpClient.HttpPost("https://lab.magiconch.com/api/nbnhhsh/guess", 50 | new Dictionary 51 | { 52 | ["text"] = text 53 | } 54 | ); 55 | 56 | if (result.Length == 0 || result.All(k => k.Trans == null) && result.All(k => k.Inputting == null)) 57 | return Reply("未检测到结果"); 58 | 59 | var ret = string.Join("\r\n", result 60 | .Where(k => k.Trans != null || k.Inputting != null) 61 | .Select(k => 62 | { 63 | var sb = new StringBuilder(k.Name + ": "); 64 | if (k.Trans != null) 65 | { 66 | sb.Append(string.Join(",", k.Trans)); 67 | } 68 | else if (k.Inputting != null) 69 | { 70 | sb.Append(string.Join(",", k.Inputting.Select(o => o + " (大概?)"))); 71 | } 72 | 73 | return sb.ToString(); 74 | })); 75 | return Reply(ret); 76 | } 77 | 78 | private class Result 79 | { 80 | [JsonPropertyName("name")] 81 | public string Name { get; set; } 82 | 83 | [JsonPropertyName("trans")] 84 | public string[]? Trans { get; set; } 85 | 86 | [JsonPropertyName("inputting")] 87 | public string[]? Inputting { get; set; } 88 | } 89 | } -------------------------------------------------------------------------------- /daylily/Plugins/Basic/Echo.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using MilkiBotFramework.Messaging; 3 | using MilkiBotFramework.Plugining; 4 | using MilkiBotFramework.Plugining.Attributes; 5 | 6 | namespace daylily.Plugins.Basic; 7 | 8 | [PluginIdentifier("14f02b6a-44d5-4064-9e9d-c04796793ec7", "Ping-pong")] 9 | [Description("ping-pong!")] 10 | public class Echo : BasicPlugin 11 | { 12 | [CommandHandler("echo", Authority = MessageAuthority.Root)] 13 | public IResponse EchoHandler([Argument] string content, MessageContext context) 14 | { 15 | return Reply(context.CommandLineResult.SimpleArgument.ToString()); 16 | } 17 | } -------------------------------------------------------------------------------- /daylily/Plugins/Basic/HelpPlugin/HelpDetailControl.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | using System.Windows.Data; 9 | using System.Windows.Documents; 10 | using System.Windows.Input; 11 | using System.Windows.Media; 12 | using System.Windows.Media.Imaging; 13 | using System.Windows.Navigation; 14 | using System.Windows.Shapes; 15 | using MilkiBotFramework.Imaging.Wpf; 16 | using Image = SixLabors.ImageSharp.Image; 17 | 18 | namespace daylily.Plugins.Basic.HelpPlugin 19 | { 20 | /// 21 | /// HelpDetailControl.xaml 的交互逻辑 22 | /// 23 | public sealed partial class HelpDetailControl : WpfDrawingControl 24 | { 25 | private readonly HelpDetailVm _viewModel; 26 | 27 | public HelpDetailControl(object viewModel, Image? sourceImage = null) 28 | : base(viewModel, sourceImage) 29 | { 30 | InitializeComponent(); 31 | Loaded += async (_, _) => await FinishDrawing(); 32 | _viewModel = (HelpDetailVm)ViewModel; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /daylily/Plugins/Basic/HelpPlugin/HelpDetailVm.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | namespace daylily.Plugins.Basic.HelpPlugin; 4 | 5 | public sealed class HelpDetailVm 6 | { 7 | public HelpDetailVm(PluginDetailVm pluginVm,char commandFlag) 8 | { 9 | PluginVm = pluginVm; 10 | CommandFlag = commandFlag; 11 | } 12 | 13 | public string AppName { get; } = Assembly.GetEntryAssembly()?.GetName().Name ?? "DynamicBot"; 14 | 15 | public string VersionString { get; } = Assembly.GetEntryAssembly() 16 | ?.GetCustomAttribute()?.InformationalVersion ?? "0.0.1-alpha"; 17 | 18 | public string CoreVersionString { get; } = typeof(MilkiBotFramework.Bot).Assembly 19 | .GetCustomAttribute()?.InformationalVersion ?? "0.0.1-alpha"; 20 | 21 | public PluginDetailVm PluginVm { get; } 22 | 23 | public char CommandFlag { get; } 24 | //= new() 25 | //{ 26 | // Name = "那没事了", 27 | // Helps = new List() { "demo help", "multi sentences" }, 28 | // Commands = new List() 29 | // { 30 | // new CommandDefinition("nmsl", "你聋了", false), 31 | // new CommandDefinition("wslnm", "龙图小将", true), 32 | // }, 33 | // FreeArgs = new List() 34 | // { 35 | // new StringKeyValuePair() { Key = "image", Value = null }, 36 | // }, 37 | // Args = new List() 38 | // { 39 | // new StringKeyValuePair() { Key = "x", Value = "抖动X范围" }, 40 | // new StringKeyValuePair() { Key = "y", Value = "抖动Y范围" } 41 | // }, 42 | // Authors = new[] { "lyt555", "test" }, 43 | // Regexes = new List() 44 | // { 45 | // new RegexDefinition("test", "nmsl") 46 | // }, 47 | // State = PluginVersion.Alpha, 48 | // Version = "1.0.0", 49 | // Usage = "[-x x_range] [image]", 50 | // CommandFlag = AppSettings.Default?.BotSettings.CommandFlag, 51 | // DefaultCommand = "lyt555" 52 | //}; 53 | } -------------------------------------------------------------------------------- /daylily/Plugins/Basic/HelpPlugin/HelpListControl.xaml: -------------------------------------------------------------------------------- 1 |  17 | 18 | 19 | 20 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 52 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 71 | 75 | 76 | 77 | 78 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 109 | 113 | 114 | 115 | 119 | 120 | 121 | 122 | 123 | -------------------------------------------------------------------------------- /daylily/Plugins/Basic/HelpPlugin/HelpListControl.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | using System.Windows.Data; 9 | using System.Windows.Documents; 10 | using System.Windows.Input; 11 | using System.Windows.Media; 12 | using System.Windows.Media.Imaging; 13 | using System.Windows.Navigation; 14 | using System.Windows.Shapes; 15 | using MilkiBotFramework.Imaging.Wpf; 16 | using Image = SixLabors.ImageSharp.Image; 17 | 18 | namespace daylily.Plugins.Basic.HelpPlugin 19 | { 20 | /// 21 | /// HelpListControl.xaml 的交互逻辑 22 | /// 23 | public sealed partial class HelpListControl : WpfDrawingControl 24 | { 25 | private readonly HelpListVm _viewModel; 26 | 27 | public HelpListControl(object viewModel, Image? sourceImage = null) 28 | : base(viewModel, sourceImage) 29 | { 30 | InitializeComponent(); 31 | Loaded += async (_, _) => await FinishDrawing(); 32 | _viewModel = (HelpListVm)ViewModel; 33 | } 34 | 35 | private void HelpListControl_OnInitialized(object? sender, EventArgs e) 36 | { 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /daylily/Plugins/Basic/HelpPlugin/HelpListVm.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | namespace daylily.Plugins.Basic.HelpPlugin; 4 | 5 | public sealed class HelpListVm 6 | { 7 | public HelpListVm(IReadOnlyList assemblyInfoVms, char commandFlag) 8 | { 9 | AssemblyInfoVms = assemblyInfoVms; 10 | CommandFlag = commandFlag; 11 | } 12 | 13 | public string AppName { get; } = Assembly.GetEntryAssembly()?.GetName().Name ?? "DynamicBot"; 14 | 15 | public string VersionString { get; } = Assembly.GetEntryAssembly() 16 | ?.GetCustomAttribute()?.InformationalVersion ?? "0.0.1-alpha"; 17 | 18 | public string CoreVersionString { get; } = typeof(MilkiBotFramework.Bot).Assembly 19 | .GetCustomAttribute()?.InformationalVersion ?? "0.0.1-alpha"; 20 | 21 | public IReadOnlyList AssemblyInfoVms { get; } 22 | 23 | public char CommandFlag { get; } 24 | } -------------------------------------------------------------------------------- /daylily/Plugins/Basic/HelpPlugin/PluginDetailVm.cs: -------------------------------------------------------------------------------- 1 | using MilkiBotFramework.Plugining.Loading; 2 | 3 | namespace daylily.Plugins.Basic.HelpPlugin; 4 | 5 | public class PluginDetailVm 6 | { 7 | public PluginDetailVm(string name, string? description, string authors, PluginInfo pluginInfo, 8 | IReadOnlyCollection commands, CommandInfo? currentCommand) 9 | { 10 | Name = name; 11 | Description = description; 12 | Authors = authors; 13 | PluginInfo = pluginInfo; 14 | Commands = commands; 15 | CurrentCommand = currentCommand; 16 | } 17 | 18 | public string Name { get; } 19 | public string? Description { get; } 20 | public string Authors { get; } 21 | //public List Regexes { get; set; } 22 | public PluginInfo PluginInfo { get; } 23 | public IReadOnlyCollection Commands { get; } 24 | public CommandInfo? CurrentCommand { get; } 25 | public string? CurrentCommandUsage { get; set; } 26 | public IReadOnlyList CurrentArguments { get; set; } = Array.Empty(); 27 | public IReadOnlyList CurrentOptions { get; set; } = Array.Empty(); 28 | } -------------------------------------------------------------------------------- /daylily/Plugins/Basic/HelpPlugin/PluginInfoVm.cs: -------------------------------------------------------------------------------- 1 | using MilkiBotFramework.Plugining.Loading; 2 | 3 | namespace daylily.Plugins.Basic.HelpPlugin; 4 | 5 | public sealed class PluginInfoVm 6 | { 7 | public PluginInfoVm(PluginInfo pluginInfo, IReadOnlyList commands) 8 | { 9 | PluginInfo = pluginInfo; 10 | Commands = commands; 11 | } 12 | 13 | public PluginInfo PluginInfo { get; } 14 | public IReadOnlyList Commands { get; } 15 | } -------------------------------------------------------------------------------- /daylily/Plugins/Basic/HelpPlugin/ScopeInfoVm.cs: -------------------------------------------------------------------------------- 1 | namespace daylily.Plugins.Basic.HelpPlugin; 2 | 3 | public sealed class ScopeInfoVm 4 | { 5 | public ScopeInfoVm(string scope, IReadOnlyList pluginInfos) 6 | { 7 | Scope = scope; 8 | PluginInfos = pluginInfos; 9 | } 10 | 11 | public string Scope { get; } 12 | public IReadOnlyList PluginInfos { get; } 13 | } -------------------------------------------------------------------------------- /daylily/Plugins/Basic/HelpPlugin/String2DescriptionConverter.cs: -------------------------------------------------------------------------------- 1 | using System.Globalization; 2 | using System.Windows.Data; 3 | 4 | namespace daylily.Plugins.Basic.HelpPlugin; 5 | 6 | public class String2DescriptionConverter : IValueConverter 7 | { 8 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 9 | { 10 | if (value is string str && !string.IsNullOrWhiteSpace(str)) 11 | return str.Trim(); 12 | return "暂无帮助信息"; 13 | } 14 | 15 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 16 | { 17 | throw new NotImplementedException(); 18 | } 19 | } -------------------------------------------------------------------------------- /daylily/Plugins/Basic/HelpPlugin/String2LowerSnakeConverter.cs: -------------------------------------------------------------------------------- 1 | using System.Globalization; 2 | using System.Windows.Data; 3 | using daylily.Utils; 4 | 5 | namespace daylily.Plugins.Basic.HelpPlugin; 6 | 7 | public class String2LowerSnakeConverter : IValueConverter 8 | { 9 | public object? Convert(object value, Type targetType, object parameter, CultureInfo culture) 10 | { 11 | if (value is string str) 12 | return str.ToLowerSnake(); 13 | return value?.ToString()?.ToLowerSnake(); 14 | } 15 | 16 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 17 | { 18 | throw new NotImplementedException(); 19 | } 20 | } -------------------------------------------------------------------------------- /daylily/Plugins/Basic/HelpPlugin/ZeroToCollapsedConverter.cs: -------------------------------------------------------------------------------- 1 | using System.Globalization; 2 | using System.Windows; 3 | using System.Windows.Data; 4 | 5 | namespace daylily.Plugins.Basic.HelpPlugin; 6 | 7 | public class ZeroToCollapsedConverter : IValueConverter 8 | { 9 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 10 | { 11 | try 12 | { 13 | var i = System.Convert.ToInt32(value); 14 | if (i == 0) return Visibility.Collapsed; 15 | return Visibility.Visible; 16 | } 17 | catch (Exception e) 18 | { 19 | return Visibility.Visible; 20 | } 21 | } 22 | 23 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 24 | { 25 | throw new NotImplementedException(); 26 | } 27 | } -------------------------------------------------------------------------------- /daylily/Plugins/Basic/KeywordTrigger.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.Diagnostics.CodeAnalysis; 3 | using System.IO; 4 | using MilkiBotFramework.Messaging; 5 | using MilkiBotFramework.Messaging.RichMessages; 6 | using MilkiBotFramework.Plugining; 7 | using MilkiBotFramework.Plugining.Attributes; 8 | using MilkiBotFramework.Plugining.Configuration; 9 | 10 | namespace daylily.Plugins.Basic; 11 | 12 | [PluginIdentifier("1abf7c43-bafb-4536-a2be-e9aff8a2fc51", "关键词触发")] 13 | [Description("收到已给的关键词时,根据已给几率返回一张熊猫图。")] 14 | public class KeywordTrigger : BasicPlugin 15 | { 16 | private readonly KeywordTriggerConfig _config; 17 | 18 | public KeywordTrigger(IConfiguration configuration) 19 | { 20 | _config = configuration.Instance; 21 | } 22 | 23 | protected override async Task OnInitialized() 24 | { 25 | _config.UserDictionary.Sort(new TriggerComparer()); 26 | _config.UserDictionary.RemoveAll(p => p == null); 27 | await _config.SaveAsync(); 28 | } 29 | 30 | public override async IAsyncEnumerable OnMessageReceived(MessageContext context) 31 | { 32 | var msg = await new RichMessage(context.GetRichMessage().Where(k => k is Text)) 33 | .EncodeAsync(); 34 | foreach (var item in _config.UserDictionary) 35 | { 36 | if (Trig(msg, item.Words, item.Pictures, out var img, item.ChancePercent)) 37 | { 38 | yield return Reply(new FileImage(Path.Combine(PluginHome, "panda", img))); 39 | yield break; 40 | } 41 | } 42 | } 43 | 44 | private static bool Trig(string message, IEnumerable keywords, IReadOnlyList pics, 45 | [NotNullWhen(true)] out string? imgP, double chancePercent = 10) 46 | { 47 | var chance = chancePercent / 100d; 48 | if (keywords.Any(k => message.Contains(k, StringComparison.InvariantCultureIgnoreCase))) 49 | { 50 | imgP = pics[Random.Shared.Next(pics.Count)]; 51 | return Random.Shared.NextDouble() < chance; 52 | } 53 | 54 | imgP = null; 55 | return false; 56 | } 57 | 58 | private class TriggerComparer : IComparer 59 | { 60 | public int Compare(KeywordTriggerConfig.TriggerObject? x, KeywordTriggerConfig.TriggerObject? y) 61 | { 62 | if (ReferenceEquals(x, y)) return 0; 63 | if (ReferenceEquals(null, y)) return 1; 64 | if (ReferenceEquals(null, x)) return -1; 65 | return x.ChancePercent.CompareTo(y.ChancePercent); 66 | } 67 | } 68 | } -------------------------------------------------------------------------------- /daylily/Plugins/Basic/Konachan.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using daylily.ThirdParty.Moebooru; 3 | using MilkiBotFramework.Connecting; 4 | using MilkiBotFramework.Messaging; 5 | using MilkiBotFramework.Messaging.RichMessages; 6 | using MilkiBotFramework.Plugining; 7 | using MilkiBotFramework.Plugining.Attributes; 8 | 9 | namespace daylily.Plugins.Basic; 10 | 11 | [PluginIdentifier("a6cbd411-499f-4dde-bdb0-fc17431cb6c9", "konachan", Authors = "bleatingsheep")] 12 | [Description("设了")] 13 | public class Konachan : BasicPlugin 14 | { 15 | private readonly LightHttpClient _lightHttpClient; 16 | 17 | public Konachan(LightHttpClient lightHttpClient) 18 | { 19 | _lightHttpClient = lightHttpClient; 20 | } 21 | 22 | [CommandHandler("konachan")] 23 | public async Task OnKonachan() 24 | { 25 | return await GetResponse("https://konachan.net"); 26 | } 27 | 28 | [CommandHandler("yandere")] 29 | public async Task OnYandere() 30 | { 31 | return await GetResponse("https://yande.re"); 32 | } 33 | 34 | private async Task GetResponse(string domain) 35 | { 36 | var k = new Api(domain); 37 | var result = await k.PopularRecentAsync(_lightHttpClient); 38 | var post = result?.FirstOrDefault(); 39 | return post == null ? null : Reply(new LinkImage(post.JpegUrl)); 40 | } 41 | } -------------------------------------------------------------------------------- /daylily/Plugins/Basic/PeroControl.xaml: -------------------------------------------------------------------------------- 1 |  15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 40 | 41 | 42 | 43 | 44 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 63 | 64 | 69 | 70 | 71 | 72 | 73 | 74 | 80 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /daylily/Plugins/Basic/PeroControl.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Windows; 8 | using System.Windows.Controls; 9 | using System.Windows.Data; 10 | using System.Windows.Documents; 11 | using System.Windows.Input; 12 | using System.Windows.Media; 13 | using System.Windows.Media.Imaging; 14 | using System.Windows.Navigation; 15 | using System.Windows.Shapes; 16 | using MilkiBotFramework.Connecting; 17 | using MilkiBotFramework.Data; 18 | using MilkiBotFramework.Imaging.Wpf; 19 | using MilkiBotFramework.Imaging; 20 | using MilkiBotFramework.Messaging.RichMessages; 21 | using MilkiBotFramework.Messaging; 22 | using MilkiBotFramework.Plugining.Attributes; 23 | using MilkiBotFramework.Plugining; 24 | using Image = SixLabors.ImageSharp.Image; 25 | using Path = System.IO.Path; 26 | 27 | namespace daylily.Plugins.Basic; 28 | 29 | [PluginIdentifier("411dd6b0-5557-4255-94ba-d31dced4a89e", "舔", Scope = "daylily", 30 | Authors = "milkiticyf")] 31 | public class Pero : BasicPlugin 32 | { 33 | private readonly LightHttpClient _lightHttpClient; 34 | 35 | public Pero(LightHttpClient lightHttpClient) 36 | { 37 | _lightHttpClient = lightHttpClient; 38 | } 39 | 40 | [CommandHandler("pero")] 41 | public async Task PeroCore(MessageContext context) 42 | { 43 | var richMsg = context.GetRichMessage(); 44 | var userId = richMsg.OfType().FirstOrDefault()?.UserId; 45 | byte[]? avatarBytes; 46 | if (userId != null) 47 | { 48 | var uri = $"http://q1.qlogo.cn/g?b=qq&nk={userId}&s=640"; 49 | (avatarBytes, _) = await _lightHttpClient.GetImageBytesFromUrlAsync(uri); 50 | } 51 | else 52 | { 53 | var firstImage = richMsg.OfType().FirstOrDefault(); 54 | if (firstImage != null) 55 | { 56 | (avatarBytes, _) = await _lightHttpClient.GetImageBytesFromUrlAsync(firstImage.Uri); 57 | } 58 | else 59 | { 60 | var qq = context.MessageUserIdentity?.UserId; 61 | var uri = $"http://q1.qlogo.cn/g?b=qq&nk={qq}&s=640"; 62 | (avatarBytes, _) = await _lightHttpClient.GetImageBytesFromUrlAsync(uri); 63 | } 64 | } 65 | 66 | var renderer = new WpfDrawingProcessor(true); 67 | 68 | var peroVm = new PeroVm(avatarBytes, Path.Combine(PluginHome, "base.png")); 69 | var image = await renderer.ProcessAsync(peroVm); 70 | return Reply(new MemoryImage(image, ImageType.Png)); 71 | } 72 | } 73 | 74 | public class PeroVm : ViewModelBase 75 | { 76 | private ImageSource? _avatar; 77 | 78 | public PeroVm(byte[] avatarBytes, string baseImagePath) 79 | { 80 | AvatarBytes = avatarBytes; 81 | BaseImagePath = Path.GetFullPath(baseImagePath); 82 | } 83 | 84 | public string BaseImagePath { get; } 85 | public byte[] AvatarBytes { get; } 86 | public ImageSource? Avatar 87 | { 88 | get => _avatar; 89 | set => SetField(ref _avatar, value); 90 | } 91 | } 92 | 93 | /// 94 | /// PeroControl.xaml 的交互逻辑 95 | /// 96 | public partial class PeroControl : WpfDrawingControl 97 | { 98 | private readonly PeroVm _viewModel; 99 | 100 | public PeroControl(object viewModel, Image? sourceImage = null) 101 | : base(viewModel, sourceImage) 102 | { 103 | InitializeComponent(); 104 | Loaded += async (_, _) => await FinishDrawing(); 105 | _viewModel = (PeroVm)ViewModel; 106 | 107 | var memoryStream = new MemoryStream(_viewModel.AvatarBytes); 108 | var bitmapSource = new BitmapImage(); 109 | 110 | bitmapSource.BeginInit(); 111 | bitmapSource.StreamSource = memoryStream; 112 | bitmapSource.CacheOption = BitmapCacheOption.None; 113 | bitmapSource.EndInit(); 114 | 115 | _viewModel.Avatar = bitmapSource; 116 | } 117 | } -------------------------------------------------------------------------------- /daylily/Plugins/Basic/Roll.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using MilkiBotFramework.Messaging; 3 | using MilkiBotFramework.Plugining; 4 | using MilkiBotFramework.Plugining.Attributes; 5 | 6 | namespace daylily.Plugins.Basic; 7 | 8 | [PluginIdentifier("bbcfc459-20b2-483b-89be-d7fe3289010d", "获取随机数")] 9 | [Description("获取一个或多个随机数。")] 10 | public class Roll : BasicPlugin 11 | { 12 | [CommandHandler("roll")] 13 | public IResponse RollNumbers( 14 | [Option("r"), Description("若启用,则使抽取含重复结果。否则结果不包含重复结果。")] 15 | bool repeat = false, 16 | [Argument, Description("当参数(m)为无效参数时,此参数(n)为上界(0~n)。否则此参数为下界(n~m)。")] 17 | int? param1 = null, 18 | [Argument, Description("此参数(m)为上界(n~m)。")] 19 | int? param2 = null, 20 | [Argument, Description("此参数(c)为抽取的数量。")] 21 | int? count = null) 22 | { 23 | var rand = Random.Shared; 24 | 25 | if (param1 == null) 26 | return Reply(GetRand(rand).ToString()); 27 | if (param2 == null) 28 | return Reply(GetRand(param1.Value, rand).ToString()); 29 | if (count == null) 30 | return Reply(GetRand(param1.Value, param2.Value, rand).ToString()); 31 | return Reply(GetRandMessage(param1.Value, param2.Value, repeat, count.Value, rand)); 32 | } 33 | 34 | private static int GetRand(Random random) => random.Next(0, 101); 35 | 36 | private static int GetRand(int uBound, Random random) => random.Next(0, uBound + 1); 37 | 38 | private static int GetRand(int lBound, int uBound, Random random) => random.Next(lBound, uBound + 1); 39 | 40 | private static string GetRandMessage(int lBound, int uBound, bool repeat, int count, Random random) 41 | { 42 | uBound += 1; 43 | if (uBound - lBound > 1000) return "总数只支持1000以内……"; 44 | if (count > 30) return "次数不能大于30……"; 45 | if (count < 0) return "缩不粗化"; 46 | 47 | List newList = new List(); 48 | if (repeat || count > uBound - lBound) 49 | { 50 | string repMsg = ((count > uBound - lBound) || repeat) ? "(包含重复结果)" : ""; 51 | for (int i = 0; i < count; i++) 52 | { 53 | newList.Add(GetRand(lBound, uBound - 1, random)); 54 | } 55 | 56 | newList.Sort(); 57 | return repMsg + string.Join(", ", newList); 58 | } 59 | 60 | // else 61 | List list = new List(); 62 | for (int i = lBound; i < uBound; i++) 63 | list.Add(i); 64 | 65 | for (int i = 0; i < count; i++) 66 | { 67 | int index = random.Next(0, list.Count); 68 | newList.Add(list[index]); 69 | list.RemoveAt(index); 70 | } 71 | 72 | newList.Sort(); 73 | return string.Join(", ", newList); 74 | } 75 | } -------------------------------------------------------------------------------- /daylily/Plugins/Basic/RpsDice.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using MilkiBotFramework.Messaging; 3 | using MilkiBotFramework.Platforms.GoCqHttp.Messaging.CqCodes; 4 | using MilkiBotFramework.Plugining; 5 | using MilkiBotFramework.Plugining.Attributes; 6 | 7 | namespace daylily.Plugins.Basic; 8 | 9 | [PluginIdentifier("d6ba1003-4c02-46d6-94c5-52b737f7b967", "猜拳/掷骰子")] 10 | [Description("发送掷骰子或猜拳魔法表情。")] 11 | internal class RpsDice : BasicPlugin 12 | { 13 | [CommandHandler("rps")] 14 | [Description("掷骰子")] 15 | public IResponse Rps() 16 | { 17 | return Reply(CQRps.Instance); 18 | } 19 | 20 | [CommandHandler("dice")] 21 | [Description("猜拳")] 22 | public IResponse Dice() 23 | { 24 | return Reply(CQDice.Instance); 25 | } 26 | } -------------------------------------------------------------------------------- /daylily/Plugins/Basic/Smoke.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using Microsoft.Extensions.Logging; 3 | using MilkiBotFramework.ContactsManaging; 4 | using MilkiBotFramework.ContactsManaging.Models; 5 | using MilkiBotFramework.Messaging; 6 | using MilkiBotFramework.Platforms.GoCqHttp.Connecting; 7 | using MilkiBotFramework.Plugining; 8 | using MilkiBotFramework.Plugining.Attributes; 9 | 10 | namespace daylily.Plugins.Basic; 11 | 12 | [PluginIdentifier("4c729d16-3954-4e70-ad4c-8a0ea72efe1a", "自助禁言")] 13 | [Description("当${BotNick}是管理员时,将命令发送者禁言(30分钟到12小时)。")] 14 | public class Smoke : BasicPlugin 15 | { 16 | private readonly IContactsManager _contactsManager; 17 | private readonly ILogger _logger; 18 | private readonly GoCqApi _goCqApi; 19 | 20 | public Smoke(IContactsManager contactsManager, ILogger logger, GoCqApi goCqApi) 21 | { 22 | _contactsManager = contactsManager; 23 | _logger = logger; 24 | _goCqApi = goCqApi; 25 | } 26 | 27 | [CommandHandler("sleep", AllowedMessageType = MessageType.Channel)] 28 | public async Task SmokeHandler(MessageContext context, 29 | [Argument, Description("要禁言的时长,小时为单位,支持小数")] double sleepTime = 0) 30 | { 31 | var userIdentity = context.MessageUserIdentity; 32 | var messageIdentity = userIdentity!.MessageIdentity; 33 | var userId = userIdentity.UserId; 34 | var channelId = messageIdentity.Id!; 35 | 36 | var self = await _contactsManager.TryGetOrUpdateSelfInfo(); 37 | if (self.IsSuccess) 38 | { 39 | var groupMember = await _contactsManager.TryGetOrAddMemberInfo( 40 | channelId, self.SelfInfo!.UserId, messageIdentity.SubId); 41 | if (groupMember.IsSuccess) 42 | { 43 | if (groupMember.MemberInfo!.MemberRole == MemberRole.Member) 44 | { 45 | return Reply("${BotNick}不是管理员,没办法自助禁言o"); 46 | } 47 | } 48 | } 49 | 50 | if (sleepTime == 0) 51 | { 52 | return Reply("要禁多少小时?"); 53 | } 54 | 55 | if (sleepTime > 12) 56 | { 57 | sleepTime = 12; 58 | } 59 | else if (sleepTime < 0.5) 60 | { 61 | sleepTime = 0.5; 62 | } 63 | else if (sleepTime > 0) 64 | { 65 | //ignore 66 | } 67 | else 68 | { 69 | return Reply("处于4维时空的我们,可不允许在时间轴上走回头路.."); 70 | } 71 | 72 | var totalTime = TimeSpan.FromHours(sleepTime); 73 | try 74 | { 75 | await _goCqApi.SetGroupBan(long.Parse(channelId), long.Parse(userId), totalTime); 76 | } 77 | catch (Exception ex) 78 | { 79 | _logger.LogWarning(ex, "禁言时出错"); 80 | return Reply("由于不可抗力,${BotNick}没有办法禁言.."); 81 | } 82 | 83 | return Reply($"祝你一觉睡到{DateTime.Now.AddHours(sleepTime):HH:mm} 🙂"); 84 | } 85 | } -------------------------------------------------------------------------------- /daylily/Plugins/Basic/Tuling.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Concurrent; 2 | using System.ComponentModel; 3 | using daylily.ThirdParty.Tuling; 4 | using MilkiBotFramework.Messaging; 5 | using MilkiBotFramework.Messaging.RichMessages; 6 | using MilkiBotFramework.Plugining; 7 | using MilkiBotFramework.Plugining.Attributes; 8 | using MilkiBotFramework.Plugining.Configuration; 9 | using MilkiBotFramework.Tasking; 10 | 11 | namespace daylily.Plugins.Basic; 12 | 13 | [PluginIdentifier("14e60bec-dc11-45da-8654-baed42588745", "图灵")] 14 | [Description("不时进行成精发言")] 15 | [PluginLifetime(PluginLifetime.Singleton)] 16 | public class Tuling : BasicPlugin 17 | { 18 | private readonly BotTaskScheduler _taskScheduler; 19 | private readonly TulingClient _tulingClient; 20 | private readonly TulingConfig _config; 21 | 22 | public Tuling(IConfiguration configuration, 23 | BotTaskScheduler taskScheduler, 24 | TulingClient tulingClient) 25 | { 26 | _taskScheduler = taskScheduler; 27 | _tulingClient = tulingClient; 28 | _config = configuration.Instance; 29 | } 30 | 31 | protected override async Task OnInitialized() 32 | { 33 | _config.ApiInfos ??= new ConcurrentDictionary(); 34 | _taskScheduler.AddTask("ResetTuling", k => k 35 | .EachDayAt(new DateTime(1, 1, 1, 0, 0, 0, 0)) 36 | .Do(ResetCount)); 37 | } 38 | 39 | public override async IAsyncEnumerable OnMessageReceived(MessageContext context) 40 | { 41 | var rnd = Random.Shared.NextDouble(); 42 | if (rnd >= 1d / 60) 43 | { 44 | yield break; 45 | } 46 | 47 | var text = await new RichMessage(context.GetRichMessage().Where(k => k is Text)).EncodeAsync(); 48 | if (string.IsNullOrWhiteSpace(text)) 49 | { 50 | yield break; 51 | } 52 | 53 | var apiInfos = _config.ApiInfos!; 54 | var apis = apiInfos 55 | .Where(k => k.Value < 100) 56 | .Select(k => k.Key) 57 | .ToArray(); 58 | if (apis.Length == 0) 59 | { 60 | yield break; 61 | } 62 | 63 | var apiKey = apis[Random.Shared.Next(apis.Length)]; 64 | 65 | var response = await _tulingClient.SendText(apiKey, text, 66 | context.MessageUserIdentity.UserId, 67 | context.MessageIdentity.ToString()); 68 | if (response.Intent.Code == 4003) 69 | { 70 | apiInfos[apiKey] = 100; 71 | } 72 | else 73 | { 74 | apiInfos[apiKey]++; 75 | } 76 | 77 | await _config.SaveAsync(); 78 | if (response.Intent.Code != 10004) 79 | { 80 | yield break; 81 | } 82 | 83 | var result = response.Results.FirstOrDefault(); 84 | if (result?.Values.Text == null) 85 | { 86 | yield break; 87 | } 88 | 89 | var str = result.Values.Text.Trim('。', '?', '?', '!', '!', '~', '~'); 90 | await Task.Delay(Random.Shared.Next(2, 7)); 91 | yield return Reply(str, false); 92 | } 93 | 94 | private void ResetCount(TaskContext context, CancellationToken token) 95 | { 96 | foreach (var key in _config.ApiInfos.Keys) 97 | { 98 | _config.ApiInfos[key] = 0; 99 | } 100 | 101 | _config.SaveAsync().Wait(token); 102 | } 103 | } -------------------------------------------------------------------------------- /daylily/Plugins/Core/CliPrint.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using Microsoft.Extensions.Logging; 3 | using MilkiBotFramework.Messaging; 4 | using MilkiBotFramework.Plugining; 5 | using MilkiBotFramework.Plugining.Attributes; 6 | 7 | namespace daylily.Plugins.Core; 8 | 9 | [PluginIdentifier("9a71f0a2-fd2e-4d7e-abd8-681d14d0d83e", "控制台消息输出", AllowDisable = false, Index = -99)] 10 | [PluginLifetime(PluginLifetime.Singleton)] 11 | [Description("用于后台DEBUG")] 12 | public class CliPrint : BasicPlugin 13 | { 14 | private readonly ILogger _logger; 15 | 16 | public CliPrint(ILoggerFactory loggerFactory) 17 | { 18 | _logger = loggerFactory.CreateLogger("raw"); 19 | } 20 | 21 | public override IAsyncEnumerable OnMessageReceived(MessageContext context) 22 | { 23 | var identity = context.MessageIdentity!; 24 | string session = "未知会话"; 25 | string sender = "未知发送者"; 26 | 27 | if (identity.MessageType == MessageType.Private) 28 | { 29 | var privateInfo = context.PrivateInfo!; 30 | session = "私聊 " + privateInfo.UserId + " - " + 31 | (privateInfo.Remark ?? privateInfo.Nickname ?? privateInfo.UserId); 32 | sender = "对方"; 33 | } 34 | else if (identity.MessageType == MessageType.Channel) 35 | { 36 | var channelInfo = context.ChannelInfo!; 37 | var memberInfo = context.MemberInfo!; 38 | session = identity.SubId == null 39 | ? $"群 {channelInfo.ChannelId} - {channelInfo.Name}" 40 | : $"频道 {channelInfo.ChannelId}.{channelInfo.SubChannelId} - {channelInfo.Name}"; 41 | var name = memberInfo.Card ?? memberInfo.Nickname ?? memberInfo.UserId; 42 | sender = name == memberInfo.UserId ? name : name + $" ({memberInfo.UserId})"; 43 | } 44 | 45 | var richMessage = context.GetRichMessage().ToString(); 46 | var actualMessage = string.Join('\n', richMessage.Split('\n').Select(k => " " + k)); 47 | 48 | _logger.LogInformation($"{context.ReceivedTime.LocalDateTime} ({session}) {sender}:\r\n" + 49 | $"{actualMessage}"); 50 | 51 | return base.OnMessageReceived(context); 52 | } 53 | } -------------------------------------------------------------------------------- /daylily/Plugins/Core/CommandRate.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using MilkiBotFramework.Messaging; 3 | using MilkiBotFramework.Plugining; 4 | using MilkiBotFramework.Plugining.Attributes; 5 | using MilkiBotFramework.Plugining.Configuration; 6 | 7 | namespace daylily.Plugins.Core; 8 | 9 | [PluginIdentifier("fe577f01-b63f-45e2-88bd-3236224b93b9", "命令统计", Index = -10, AllowDisable = false)] 10 | [Description("统计命令的使用情况,分析常用命令")] 11 | public class CommandRate : BasicPlugin 12 | { 13 | private readonly IConfiguration _config; 14 | 15 | public CommandRate(IConfiguration config) 16 | { 17 | _config = config; 18 | } 19 | 20 | public override async IAsyncEnumerable OnMessageReceived(MessageContext context) 21 | { 22 | var commandLineResult = context.CommandLineResult; 23 | if (commandLineResult == null) yield break; 24 | 25 | var command = commandLineResult.Command.ToString()!; 26 | var plugin = context.NextPlugins.FirstOrDefault(k => k.Commands.ContainsKey(command)) ?? 27 | context.ExecutedPlugins.FirstOrDefault(k => k.Commands.ContainsKey(command)); 28 | 29 | if (plugin == null) yield break; 30 | 31 | _config.Instance.CommandRate.AddOrUpdate(command, 1, (_, i) => i + 1); 32 | await _config.Instance.SaveAsync(); 33 | } 34 | } -------------------------------------------------------------------------------- /daylily/Plugins/Core/GuiManaging/GuiManager.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using MilkiBotFramework; 3 | using MilkiBotFramework.Imaging.Wpf.Internal; 4 | using MilkiBotFramework.Plugining; 5 | using MilkiBotFramework.Plugining.Attributes; 6 | 7 | namespace daylily.Plugins.Core.GuiManaging; 8 | 9 | [PluginIdentifier("18bd9084-ece9-48e9-8c2d-91e26ca494de")] 10 | public class GuiManager : ServicePlugin 11 | { 12 | private readonly Bot _bot; 13 | private readonly PluginManager _pluginManager; 14 | 15 | public GuiManager(Bot bot, PluginManager pluginManager) 16 | { 17 | _bot = bot; 18 | _pluginManager = pluginManager; 19 | } 20 | 21 | protected override async Task OnInitialized() 22 | { 23 | await UiThreadHelper.EnsureUiThreadAsync(); 24 | await Application.Current.Dispatcher.InvokeAsync(() => 25 | { 26 | var managerWindow = new ManagerWindow(_bot, _pluginManager.GetAllPlugins()); 27 | managerWindow.Show(); 28 | }); 29 | } 30 | } -------------------------------------------------------------------------------- /daylily/Plugins/Core/GuiManaging/ManagerWindow.xaml: -------------------------------------------------------------------------------- 1 |  16 | 17 | 18 | 19 | 20 | 21 | 22 | 26 |