From 1957842d4c32cf3f0274da335b934b233aca6e03 Mon Sep 17 00:00:00 2001
From: Toastie <toastie@toastiet0ast.com>
Date: Wed, 4 Dec 2024 00:09:08 +1300
Subject: [PATCH] Added social marmalade.

---
 .gitignore           |   1 +
 Social/.gitignore    |   4 ++
 Social/NuGet.Config  |   6 ++
 Social/Social.cs     | 150 +++++++++++++++++++++++++++++++++++++++++++
 Social/Social.csproj |  40 ++++++++++++
 Social/WaifuData.cs  |   8 +++
 Social/cmds.yml      |  49 ++++++++++++++
 Social/res.yml       |   1 +
 8 files changed, 259 insertions(+)
 create mode 100644 .gitignore
 create mode 100644 Social/.gitignore
 create mode 100644 Social/NuGet.Config
 create mode 100644 Social/Social.cs
 create mode 100644 Social/Social.csproj
 create mode 100644 Social/WaifuData.cs
 create mode 100644 Social/cmds.yml
 create mode 100644 Social/res.yml

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..e986a3b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+*.sln
\ No newline at end of file
diff --git a/Social/.gitignore b/Social/.gitignore
new file mode 100644
index 0000000..af19d79
--- /dev/null
+++ b/Social/.gitignore
@@ -0,0 +1,4 @@
+obj/
+bin/
+.idea/
+.vs/
\ No newline at end of file
diff --git a/Social/NuGet.Config b/Social/NuGet.Config
new file mode 100644
index 0000000..7fc1859
--- /dev/null
+++ b/Social/NuGet.Config
@@ -0,0 +1,6 @@
+<configuration>
+    <packageSources>
+        <add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
+        <add key="toastielab.dev" value="https://toastielab.dev/api/packages/ellie/nuget/index.json" protocolVersion="3" />
+    </packageSources>
+</configuration>
\ No newline at end of file
diff --git a/Social/Social.cs b/Social/Social.cs
new file mode 100644
index 0000000..11c14fc
--- /dev/null
+++ b/Social/Social.cs
@@ -0,0 +1,150 @@
+using System.Net.Http.Json;
+using Discord;
+using EllieBot.Marmalade;
+
+namespace Social;
+
+public sealed class Social : Canary
+{
+    public new string Name = "Social";
+    private static readonly HttpClient Client = new HttpClient();
+
+    [svc(Lifetime.Singleton)]
+    public sealed class SocialService
+    {
+        public async Task<string> GetWaifuPicsImage(ImageType imageType)
+        {
+            var img = await Client
+                .GetFromJsonAsync<WaifuData>($"https://waifu.pics/api/sfw/{imageType}")
+                .ConfigureAwait(false);
+
+            return img.URL;
+        }
+
+        public async Task SendWaifuPicsEmbedAsync(AnyContext ctx, ImageType imageType, string text = null)
+        {
+            var emb = new EmbedBuilder();
+
+            await ctx.Channel.TriggerTypingAsync().ConfigureAwait(false);
+
+            var img = await GetWaifuPicsImage(imageType);
+
+            if (!string.IsNullOrWhiteSpace(img))
+            {
+                emb.WithImageUrl(img);
+            }
+
+            if (!string.IsNullOrWhiteSpace(text))
+            {
+                switch (imageType)
+                {
+                    case ImageType.hug:
+                        emb.WithDescription($"{ctx.User.Mention} hugged {text}");
+                        break;
+                    case ImageType.pat:
+                        emb.WithDescription($"{ctx.User.Mention} petted {text}");
+                        break;
+                    case ImageType.kiss:
+                        emb.WithDescription($"{ctx.User.Mention} kissed {text}");
+                        break;
+                    case ImageType.wave:
+                        emb.WithDescription($"{ctx.User.Mention} waved to {text}");
+                        break;
+                    case ImageType.cuddle:
+                        emb.WithDescription($"{ctx.User.Mention} cuddled {text}");
+                        break;
+                }
+            }
+            await ctx.Channel.EmbedAsync(emb);
+        }
+
+        public async Task SendWaifuPicsEmbedAsync(AnyContext ctx, ImageType imageType)
+        {
+            var emb = new EmbedBuilder();
+
+            await ctx.Channel.TriggerTypingAsync().ConfigureAwait(false);
+
+            var img = await GetWaifuPicsImage(imageType);
+
+            if (!string.IsNullOrWhiteSpace(img))
+            {
+                emb.WithImageUrl(img);
+            }
+
+            await ctx.Channel.EmbedAsync(emb);
+        }
+    }
+
+    public enum ImageType
+    {
+        hug,
+        pat,
+        kiss,
+        wave,
+        cuddle,
+        waifu,
+        neko,
+        shinobu,
+        megumin
+    }
+
+    public sealed class SocialInteractions(SocialService service) : Canary
+    {
+        [cmd]
+        public async Task Hug(AnyContext ctx, [leftover] string text = null)
+        {
+            await service.SendWaifuPicsEmbedAsync(ctx, ImageType.hug, text);
+        }
+
+        [cmd]
+        public async Task Pat(AnyContext ctx, [leftover] string text = null)
+        {
+            await service.SendWaifuPicsEmbedAsync(ctx, ImageType.pat, text);
+        }
+
+        [cmd]
+        public async Task Kiss(AnyContext ctx, [leftover] string text = null)
+        {
+            await service.SendWaifuPicsEmbedAsync(ctx, ImageType.kiss, text);
+        }
+
+        [cmd]
+        public async Task Wave(AnyContext ctx, [leftover] string text = null)
+        {
+            await service.SendWaifuPicsEmbedAsync(ctx, ImageType.wave, text);
+        }
+
+        [cmd]
+        public async Task Cuddle(AnyContext ctx, [leftover] string text = null)
+        {
+            await service.SendWaifuPicsEmbedAsync(ctx, ImageType.cuddle, text);
+        }
+    }
+
+    public sealed class Images(SocialService service) : Canary
+    {
+        [cmd]
+        public async Task Waifu(AnyContext ctx)
+        {
+            await service.SendWaifuPicsEmbedAsync(ctx, ImageType.waifu);
+        }
+
+        [cmd]
+        public async Task Neko(AnyContext ctx)
+        {
+            await service.SendWaifuPicsEmbedAsync(ctx, ImageType.neko);
+        }
+
+        [cmd]
+        public async Task Shinobu(AnyContext ctx)
+        {
+            await service.SendWaifuPicsEmbedAsync(ctx, ImageType.shinobu);
+        }
+
+        [cmd]
+        public async Task Megumin(AnyContext ctx)
+        {
+            await service.SendWaifuPicsEmbedAsync(ctx, ImageType.megumin);
+        }
+    }
+}
\ No newline at end of file
diff --git a/Social/Social.csproj b/Social/Social.csproj
new file mode 100644
index 0000000..bfb7e57
--- /dev/null
+++ b/Social/Social.csproj
@@ -0,0 +1,40 @@
+<Project Sdk="Microsoft.NET.Sdk">
+    <PropertyGroup>
+        <TargetFramework>net8.0</TargetFramework>
+
+        <!-- Reduces some boilerplate in your .cs files -->
+        <ImplicitUsings>enable</ImplicitUsings>
+
+        <!-- Use latest .net features -->
+        <LangVersion>preview</LangVersion>
+        <EnablePreviewFeatures>true</EnablePreviewFeatures>
+        <GenerateRequiresPreviewFeaturesAttribute>true</GenerateRequiresPreviewFeaturesAttribute>
+
+        <!-- tell .net that this library will be used as a plugin -->
+        <EnableDynamicLoading>true</EnableDynamicLoading>
+        <RootNamespace>Social</RootNamespace>
+    </PropertyGroup>
+
+    <ItemGroup>
+        <!-- Base marmalade package. You MUST reference this in order to have a working marmalade -->
+        <!-- Also, this package comes from Toastielab, which requires you to have a NuGet.Config file next to your .csproj -->
+        <PackageReference Include="Ellie.Marmalade" Version="5.2.4">
+            <PrivateAssets>all</PrivateAssets>
+        </PackageReference>
+
+        <!-- Note: If you want to use EllieBot services etc... You will have to manually clone
+          the https://toastielab.dev/Emotions-stuff/elliebot repo locally and reference the EllieBot.csproj because there is no EllieBot package atm.
+          It is strongly recommended that you checkout a specific tag which matches your version of ellie,
+          as there could be breaking changes even between minor versions of EllieBot.
+          For example if you're running EllieBot 4.1.0 locally for which you want to create a marmalade for,
+          you should do "git checkout 4.1.0" in your EllieBot solution and then reference the EllieBot.csproj
+        -->
+    </ItemGroup>
+
+    <!-- Copy shortcut and full strings to output (if they exist) -->
+    <ItemGroup>
+        <None Update="res.yml;cmds.yml;strings/**">
+            <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+        </None>
+    </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/Social/WaifuData.cs b/Social/WaifuData.cs
new file mode 100644
index 0000000..943782d
--- /dev/null
+++ b/Social/WaifuData.cs
@@ -0,0 +1,8 @@
+using System.Text.Json.Serialization;
+
+namespace Social;
+
+public class WaifuData
+{
+    [JsonPropertyName("url")] public string URL { get; set; }
+}
\ No newline at end of file
diff --git a/Social/cmds.yml b/Social/cmds.yml
new file mode 100644
index 0000000..d2c6ed1
--- /dev/null
+++ b/Social/cmds.yml
@@ -0,0 +1,49 @@
+hug:
+  desc: "Hug a friend!"
+  args:
+    - ""
+    - "@someone"
+
+kiss:
+  desc: "K-kiss someone s-special!"
+  args:
+    - ""
+    - "@someone"
+
+pat:
+  desc: "A good boy deserves pats."
+  args:
+    - ""
+    - "@someone"
+
+cuddle:
+  desc: "Cuddle your lover. ...Or yourself."
+  args:
+    - ""
+    - "@someone"
+
+wave:
+  desc: "Greet your friends with a friendly wave."
+  args:
+    - ""
+    - "@someone"
+
+waifu:
+  desc: "Spawn a random waifu!"
+  args:
+    - ""
+
+neko:
+  desc: "Spawn a random catgirl!"
+  args:
+    - ""
+
+shinobu:
+  desc: "Little vampire girl"
+  args:
+    - ""
+
+megumin:
+  desc: "Explosive girl"
+  args:
+    - ""
diff --git a/Social/res.yml b/Social/res.yml
new file mode 100644
index 0000000..db2618d
--- /dev/null
+++ b/Social/res.yml
@@ -0,0 +1 @@
+marmalade.description: "Images and interactions module - For interacting with members and getting nice pictures."
\ No newline at end of file