diff --git a/Booru.Net.sln b/Booru.Net.sln
new file mode 100644
index 0000000..78bbf4d
--- /dev/null
+++ b/Booru.Net.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.27703.2026
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Booru.Net", "Booru.Net\Booru.Net.csproj", "{BC612FDE-FC2D-42D8-AD7F-988874B6A839}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {BC612FDE-FC2D-42D8-AD7F-988874B6A839}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {BC612FDE-FC2D-42D8-AD7F-988874B6A839}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {BC612FDE-FC2D-42D8-AD7F-988874B6A839}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {BC612FDE-FC2D-42D8-AD7F-988874B6A839}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {0B4AF3C1-293A-4372-B24C-A3535F49FEC3}
+ EndGlobalSection
+EndGlobal
diff --git a/Booru.Net/Booru.Net.csproj b/Booru.Net/Booru.Net.csproj
new file mode 100644
index 0000000..e3ac633
--- /dev/null
+++ b/Booru.Net/Booru.Net.csproj
@@ -0,0 +1,15 @@
+
+
+
+ netstandard2.0
+ false
+ exsersewo
+
+
+
+
+
+
+
+
+
diff --git a/Booru.Net/Client.cs b/Booru.Net/Client.cs
new file mode 100644
index 0000000..b62d401
--- /dev/null
+++ b/Booru.Net/Client.cs
@@ -0,0 +1,125 @@
+using System;
+using System.Linq;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Newtonsoft.Json;
+
+namespace Booru.Net
+{
+ public class Client
+ {
+ public async Task> GetSafebooruImagesAsync(IReadOnlyList tags)
+ {
+ IList newtags = tags.ToList();
+ var tagstring = String.Join("%20", newtags);
+
+ var data = await WebRequest.ReturnStringAsync(new Uri("https://safebooru.org/index.php?page=dapi&s=post&q=index&json=1&tags=" + tagstring));
+
+ if (data != null)
+ {
+ var posts = JsonConvert.DeserializeObject>(data);
+ return posts;
+ }
+
+ return null;
+ }
+ public async Task> GetRule34ImagesAsync(IReadOnlyList tags)
+ {
+ IList newtags = tags.ToList();
+ var tagstring = String.Join("%20", newtags);
+
+ var data = await WebRequest.ReturnStringAsync(new Uri("https://rule34.xxx/index.php?page=dapi&s=post&q=index&json=1&tags=" + tagstring));
+ if (data != null)
+ {
+ var posts = JsonConvert.DeserializeObject>(data);
+ return posts;
+ }
+
+ return null;
+ }
+ public async Task> GetRealBooruImagesAsync(IReadOnlyList tags)
+ {
+ IList newtags = tags.ToList();
+ var tagstring = String.Join("%20", newtags);
+
+ var data = await WebRequest.ReturnStringAsync(new Uri("https://realbooru.com/index.php?page=dapi&s=post&q=index&json=1&tags=" + tagstring));
+ if (data != null)
+ {
+ var posts = JsonConvert.DeserializeObject>(data);
+ return posts;
+ }
+
+ return null;
+ }
+ public async Task> GetDanbooruImagesAsync(IReadOnlyList tags)
+ {
+ IList newtags = tags.ToList();
+ var tagstring = String.Join("%20", newtags);
+
+ var data = await WebRequest.ReturnStringAsync(new Uri("https://danbooru.donmai.us/posts.json?tags=" + tagstring));
+ if (data != null)
+ {
+ var posts = JsonConvert.DeserializeObject>(data);
+ return posts;
+ }
+
+ return null;
+ }
+ public async Task> GetGelbooruImagesAsync(IReadOnlyList tags)
+ {
+ IList newtags = tags.ToList();
+ var tagstring = String.Join("%20", newtags);
+
+ var data = await WebRequest.ReturnStringAsync(new Uri("https://gelbooru.com/index.php?page=dapi&s=post&q=index&json=1&tags=" + tagstring));
+
+ if (data != null)
+ {
+ var posts = JsonConvert.DeserializeObject>(data);
+ return posts;
+ }
+ else return null;
+ }
+ public async Task> GetKonaChanImagesAsync(IReadOnlyList tags)
+ {
+ IList newtags = tags.ToList();
+ var tagstring = String.Join("%20", newtags);
+
+ var data = await WebRequest.ReturnStringAsync(new Uri("https://konachan.com/post.json?tags=" + tagstring));
+
+ if (data != null)
+ {
+ var posts = JsonConvert.DeserializeObject>(data);
+ return posts;
+ }
+ else return null;
+ }
+ public async Task> GetE621ImagesAsync(IReadOnlyList tags)
+ {
+ IList newtags = tags.ToList();
+ var tagstring = String.Join("%20", newtags);
+
+ var data = await WebRequest.ReturnStringAsync(new Uri("https://e621.net/post/index.json?tags=" + tagstring));
+
+ if (data != null)
+ {
+ var posts = JsonConvert.DeserializeObject>(data);
+ return posts;
+ }
+ else return null;
+ }
+ public async Task> GetYandereImagesAsync(IReadOnlyList tags)
+ {
+ IList newtags = tags.ToList();
+ var tagstring = String.Join("%20", newtags);
+
+ var data = await WebRequest.ReturnStringAsync(new Uri("https://yande.re/post.json?tags=" + tagstring));
+
+ if (data != null)
+ {
+ var posts = JsonConvert.DeserializeObject>(data);
+ return posts;
+ }
+ else return null;
+ }
+ }
+}
diff --git a/Booru.Net/Models/Boards/BooruImage.cs b/Booru.Net/Models/Boards/BooruImage.cs
new file mode 100644
index 0000000..060da94
--- /dev/null
+++ b/Booru.Net/Models/Boards/BooruImage.cs
@@ -0,0 +1,39 @@
+using Newtonsoft.Json;
+
+namespace Booru.Net
+{
+ public class BooruImage
+ {
+ [JsonProperty("id")]
+ public int ID { get; set; }
+
+ [JsonProperty("score")]
+ public int Score { get; set; }
+
+ [JsonProperty("rating")]
+ private string Prating { get; set; }
+
+ [JsonProperty("file_url")]
+ public string ImageUrl { get; set; }
+
+ public Rating Rating
+ {
+ get
+ {
+ if(Prating == "s")
+ {
+ return Rating.Safe;
+ }
+ if(Prating == "q")
+ {
+ return Rating.Questionable;
+ }
+ if(Prating == "e")
+ {
+ return Rating.Explicit;
+ }
+ return Rating.None;
+ }
+ }
+ }
+}
diff --git a/Booru.Net/Models/Boards/DanBooruImage.cs b/Booru.Net/Models/Boards/DanBooruImage.cs
new file mode 100644
index 0000000..51cc278
--- /dev/null
+++ b/Booru.Net/Models/Boards/DanBooruImage.cs
@@ -0,0 +1,15 @@
+using Newtonsoft.Json;
+using System.Collections.Generic;
+
+namespace Booru.Net
+{
+ public class DanbooruImage : BooruImage
+ {
+ [JsonProperty("tag_string")]
+ private string TagString { get; set; }
+
+ public IReadOnlyList Tags { get { return TagString.Split(' '); } }
+
+ public virtual string PostUrl { get { return "https://danbooru.donmai.us/posts/" + ID; } }
+ }
+}
diff --git a/Booru.Net/Models/Boards/E621Image.cs b/Booru.Net/Models/Boards/E621Image.cs
new file mode 100644
index 0000000..e525753
--- /dev/null
+++ b/Booru.Net/Models/Boards/E621Image.cs
@@ -0,0 +1,7 @@
+namespace Booru.Net
+{
+ public class E621Image : GelbooruImage
+ {
+ public override string PostUrl { get { return "https://e621.net/post/show/" + ID; } }
+ }
+}
diff --git a/Booru.Net/Models/Boards/GelbooruImage.cs b/Booru.Net/Models/Boards/GelbooruImage.cs
new file mode 100644
index 0000000..4bb245a
--- /dev/null
+++ b/Booru.Net/Models/Boards/GelbooruImage.cs
@@ -0,0 +1,18 @@
+using Newtonsoft.Json;
+using System.Collections.Generic;
+
+namespace Booru.Net
+{
+ public class GelbooruImage : BooruImage
+ {
+ [JsonProperty("directory")]
+ public string Directory { get; set; }
+
+ [JsonProperty("tags")]
+ private string Ptags { get; set; }
+
+ public IReadOnlyList Tags { get { return Ptags.Split(' '); } }
+
+ public virtual string PostUrl { get { return "https://gelbooru.com/index.php?page=post&s=view&id=" + ID; } }
+ }
+}
\ No newline at end of file
diff --git a/Booru.Net/Models/Boards/KonaChanImage.cs b/Booru.Net/Models/Boards/KonaChanImage.cs
new file mode 100644
index 0000000..0dcf9be
--- /dev/null
+++ b/Booru.Net/Models/Boards/KonaChanImage.cs
@@ -0,0 +1,7 @@
+namespace Booru.Net
+{
+ public class KonaChanImage : GelbooruImage
+ {
+ public override string PostUrl { get { return "https://konachan.com/post/show/" + ID; } }
+ }
+}
diff --git a/Booru.Net/Models/Boards/RealBooruImage.cs b/Booru.Net/Models/Boards/RealBooruImage.cs
new file mode 100644
index 0000000..6a3714d
--- /dev/null
+++ b/Booru.Net/Models/Boards/RealBooruImage.cs
@@ -0,0 +1,10 @@
+namespace Booru.Net
+{
+ public class RealbooruImage : SafebooruImage
+ {
+ public override string ImageUrl
+ => "https://realbooru.com/images/" + Directory + "/" + Image;
+ public override string PostUrl
+ => "https://realbooru.com/index.php?page=post&s=view&id=" + ID;
+ }
+}
diff --git a/Booru.Net/Models/Boards/Rule34Image.cs b/Booru.Net/Models/Boards/Rule34Image.cs
new file mode 100644
index 0000000..fdb442a
--- /dev/null
+++ b/Booru.Net/Models/Boards/Rule34Image.cs
@@ -0,0 +1,10 @@
+namespace Booru.Net
+{
+ public class Rule34Image : SafebooruImage
+ {
+ public override string ImageUrl
+ => "https://rule34.xxx/images/" + Directory + "/" + Image;
+ public override string PostUrl
+ => "https://rule34.xxx/index.php?page=post&s=view&id=" + ID;
+ }
+}
diff --git a/Booru.Net/Models/Boards/SafebooruImage.cs b/Booru.Net/Models/Boards/SafebooruImage.cs
new file mode 100644
index 0000000..12acf41
--- /dev/null
+++ b/Booru.Net/Models/Boards/SafebooruImage.cs
@@ -0,0 +1,61 @@
+using Newtonsoft.Json;
+using System.Collections.Generic;
+
+namespace Booru.Net
+{
+ public class SafebooruImage
+ {
+ [JsonProperty("directory")]
+ public string Directory { get; set; }
+
+ [JsonProperty("hash")]
+ public string Hash { get; set; }
+
+ [JsonProperty("height")]
+ public int Height { get; set; }
+
+ [JsonProperty("id")]
+ public int ID { get; set; }
+
+ [JsonProperty("image")]
+ public string Image { get; set; }
+
+ [JsonProperty("change")]
+ public ulong Change { get; set; }
+
+ [JsonProperty("owner")]
+ public string Owner { get; set; }
+
+ [JsonProperty("parent_id")]
+ public int ParentID { get; set; }
+
+ [JsonProperty("rating")]
+ public Rating Rating { get; set; }
+
+ [JsonProperty("sample")]
+ public bool Sample { get; set; }
+
+ [JsonProperty("sample_height")]
+ public int SampleHeight { get; set; }
+
+ [JsonProperty("sample_width")]
+ public int SampleWidth { get; set; }
+
+ [JsonProperty("score")]
+ public int Score { get; set; }
+
+ [JsonProperty("tags")]
+ private string Ptags { get; set; }
+
+ [JsonProperty("width")]
+ public int Width { get; set; }
+
+ public IReadOnlyList Tags { get { return Ptags.Split(' '); } }
+
+ public virtual string ImageUrl
+ => "https://safebooru.org/images/" + Directory + "/" + Image;
+
+ public virtual string PostUrl
+ => "https://safebooru.org/index.php?page=post&s=view&id=" + ID;
+ }
+}
diff --git a/Booru.Net/Models/Boards/YandereImage.cs b/Booru.Net/Models/Boards/YandereImage.cs
new file mode 100644
index 0000000..dba174d
--- /dev/null
+++ b/Booru.Net/Models/Boards/YandereImage.cs
@@ -0,0 +1,7 @@
+namespace Booru.Net
+{
+ public class YandereImage : GelbooruImage
+ {
+ public override string PostUrl { get { return "https://yande.re/post/show/" + ID; } }
+ }
+}
diff --git a/Booru.Net/Models/BooruTypes.cs b/Booru.Net/Models/BooruTypes.cs
new file mode 100644
index 0000000..1f42814
--- /dev/null
+++ b/Booru.Net/Models/BooruTypes.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Skuld.Models.API.Booru
+{
+ public enum BooruTypes
+ {
+ Danbooru,
+ Gelbooru,
+ Rule34,
+ E621,
+ Yandere,
+ Safebooru,
+ KonaChan
+ }
+}
diff --git a/Booru.Net/Models/Rating.cs b/Booru.Net/Models/Rating.cs
new file mode 100644
index 0000000..1f0718e
--- /dev/null
+++ b/Booru.Net/Models/Rating.cs
@@ -0,0 +1,10 @@
+namespace Booru.Net
+{
+ public enum Rating
+ {
+ None,
+ Safe,
+ Questionable,
+ Explicit
+ }
+}
diff --git a/Booru.Net/WebRequest.cs b/Booru.Net/WebRequest.cs
new file mode 100644
index 0000000..1c4fd8b
--- /dev/null
+++ b/Booru.Net/WebRequest.cs
@@ -0,0 +1,49 @@
+using System;
+using System.Net;
+using System.Threading.Tasks;
+using System.IO;
+
+namespace Booru.Net
+{
+ class WebRequest
+ {
+ public static HttpWebRequest CreateWebRequest(Uri uri)
+ {
+ var cli = (HttpWebRequest)System.Net.WebRequest.Create(uri);
+
+ cli.AllowAutoRedirect = true;
+ cli.KeepAlive = false;
+ cli.Timeout = 20000;
+ cli.ProtocolVersion = HttpVersion.Version10;
+
+ return cli;
+ }
+ public static async Task ReturnStringAsync(Uri url)
+ {
+ try
+ {
+ var client = CreateWebRequest(url);
+
+ var resp = (HttpWebResponse)(await client.GetResponseAsync());
+ if (resp.StatusCode == HttpStatusCode.OK)
+ {
+ var reader = new StreamReader(resp.GetResponseStream());
+ var responce = await reader.ReadToEndAsync();
+ resp.Dispose();
+ client.Abort();
+ return responce;
+ }
+ else
+ {
+ resp.Dispose();
+ client.Abort();
+ return null;
+ }
+ }
+ catch
+ {
+ return null;
+ }
+ }
+ }
+}