From d7bc8b58f750c1a5c629915ed2097e477d204a67 Mon Sep 17 00:00:00 2001 From: Jake Mannens Date: Sat, 19 Aug 2023 00:36:30 +1000 Subject: Added basic search engine functionality --- HBContext.cs | 14 +++++++++-- MainLayout.razor | 8 +++++-- MainLayout.razor.css | 14 +++++++---- Pages/Gallery.razor | 61 +++++++++++++++++++++++++++++++++++++++++++++++ Pages/Gallery.razor.css | 8 +++++++ Pages/Index.razor | 17 ------------- Pages/Index.razor.css | 8 ------- Pages/Upload.razor | 21 ++++++++++++++++ Pages/Upload.razor.css | 28 ++++++++++++++++++++++ Program.cs | 1 + Services/SearchService.cs | 46 +++++++++++++++++++++++++++++++++++ _Imports.razor | 3 ++- 12 files changed, 195 insertions(+), 34 deletions(-) create mode 100644 Pages/Gallery.razor create mode 100644 Pages/Gallery.razor.css delete mode 100644 Pages/Index.razor delete mode 100644 Pages/Index.razor.css create mode 100644 Pages/Upload.razor create mode 100644 Pages/Upload.razor.css create mode 100644 Services/SearchService.cs diff --git a/HBContext.cs b/HBContext.cs index 04f2d1a..45b8852 100644 --- a/HBContext.cs +++ b/HBContext.cs @@ -35,8 +35,18 @@ public class HBContext : DbContext { // Seed internal tag definitions // These should NEVER change modelBuilder.Entity().HasData(new TagDefinition[] { - new() { ObjectId = -1, Source = TagSource.Internal, Name = "nsfw" }, - new() { ObjectId = -2, Source = TagSource.Internal, Name = "ingest" } + new() { + ObjectId = -1, + Guid = new("EBDAD4F8-455A-4351-8017-1D4854D6FA38"), + Source = TagSource.Internal, + Name = "nsfw" + }, + new() { + ObjectId = -2, + Guid = new("EA212801-5BCC-4C0E-814F-FB9D30DB58BC"), + Source = TagSource.Internal, + Name = "ingest" + } }); // Implicit tags need some special attention to make many<->many diff --git a/MainLayout.razor b/MainLayout.razor index bd0675b..111e307 100644 --- a/MainLayout.razor +++ b/MainLayout.razor @@ -5,9 +5,13 @@ -@*
*@ +
@Body
diff --git a/MainLayout.razor.css b/MainLayout.razor.css index e82e72e..3d03d61 100644 --- a/MainLayout.razor.css +++ b/MainLayout.razor.css @@ -20,15 +20,21 @@ div#navbar > a:active { color: var(--col-navbar-bg); } -div#navbar > input { +div#navbar form { + display: flex; + margin: 0 20px 0 auto; + min-width: 30%; +} + +div#navbar input[type="text"] { align-self: center; background: var(--col-bg); border-radius: 0; color: white; - height: 40px !important; - margin: 0 20px 0 auto; font-size: 12pt; - min-width: 30%; + height: 40px !important; + margin: 0; + width: 100%; } #content { diff --git a/Pages/Gallery.razor b/Pages/Gallery.razor new file mode 100644 index 0000000..8b1954f --- /dev/null +++ b/Pages/Gallery.razor @@ -0,0 +1,61 @@ +@page "/" +@page "/Gallery" +@inject IDbContextFactory dbFactory +@inject ISearchService searchService + +@Title + + + +
+ + +
+ +@foreach(var media in Media) { + + + +} + +@code { + [Parameter] + [SupplyParameterFromQuery(Name = "q")] + public string? Query { get; set; } + + [Parameter] + [SupplyParameterFromQuery] + public bool? Ingest { get; set; } + + private string Title { + get { + if(Query is null) + return Ingest ? "Ingest Feed" : "Gallery"; + else + return "Search Results"; + } + } + + private Media[] Media; + + protected override void OnParametersSet() => LoadMedia(); + + private void LoadMedia() { + using var db = dbFactory.CreateDbContext(); + + if(Ingest is not null && Ingest == true) { + Media = db.Media + .OrderByDescending(m => m.ObjectId) + .ToArray() + .Where(m => m.IsIngest) + .ToArray(); + } else { + if(Query is null) + Media = db.Media + .OrderByDescending(m => m.ObjectId) + .ToArray(); + else + Media = searchService.Search(Query); + } + } +} diff --git a/Pages/Gallery.razor.css b/Pages/Gallery.razor.css new file mode 100644 index 0000000..d1750b4 --- /dev/null +++ b/Pages/Gallery.razor.css @@ -0,0 +1,8 @@ +img { + margin-right: 5px; + max-height: 200px; +} + +form#upload { + padding-bottom: 30px; +} \ No newline at end of file diff --git a/Pages/Index.razor b/Pages/Index.razor deleted file mode 100644 index 4719530..0000000 --- a/Pages/Index.razor +++ /dev/null @@ -1,17 +0,0 @@ -@page "/" -@inject HBContext db; - -Gallery - - - -
- - -
- -@foreach(var media in db.Media.OrderByDescending(m => m.ObjectId)) { - - - -} diff --git a/Pages/Index.razor.css b/Pages/Index.razor.css deleted file mode 100644 index d1750b4..0000000 --- a/Pages/Index.razor.css +++ /dev/null @@ -1,8 +0,0 @@ -img { - margin-right: 5px; - max-height: 200px; -} - -form#upload { - padding-bottom: 30px; -} \ No newline at end of file diff --git a/Pages/Upload.razor b/Pages/Upload.razor new file mode 100644 index 0000000..33153d2 --- /dev/null +++ b/Pages/Upload.razor @@ -0,0 +1,21 @@ +@page "/Upload" + + + +
+ dropHover = true) + @ondragleave=@(() => dropHover = false)/> +

Drag a file to upload it

+
+ +@code { + private bool dropHover = false; + + private void FileInputChange(IFileListEntry[] files) { + } +} \ No newline at end of file diff --git a/Pages/Upload.razor.css b/Pages/Upload.razor.css new file mode 100644 index 0000000..4064467 --- /dev/null +++ b/Pages/Upload.razor.css @@ -0,0 +1,28 @@ +div#dropzone { + border-radius: 10px; + border: 3px dashed #aaa; + height: 400px; + left: 50%; + position: relative; + top: 50%; + transform: translate(-50%, -50%); + width: 700px; +} + +div#dropzone p { + color: #aaa; + display: inline-block; + left: 50%; + margin: 0; + position: relative; + top: 50%; + transform: translate(-50%, -50%); +} + +div#dropzone.drop-hover { + border: 3px dashed white; +} + +div#dropzone.drop-hover p { + color: white; +} \ No newline at end of file diff --git a/Program.cs b/Program.cs index dfc635c..4796825 100644 --- a/Program.cs +++ b/Program.cs @@ -17,6 +17,7 @@ public class Program { // Add out custom services builder.Services.AddSingleton(); builder.Services.AddDbContextFactory(); + builder.Services.AddScoped(); builder.Services.AddScoped(); var app = builder.Build(); diff --git a/Services/SearchService.cs b/Services/SearchService.cs new file mode 100644 index 0000000..8a109ea --- /dev/null +++ b/Services/SearchService.cs @@ -0,0 +1,46 @@ +using Microsoft.EntityFrameworkCore; + +namespace HyperBooru.Services; + +public interface ISearchService { + public Media[] Search(string query); +} + +public class SearchService : ISearchService { + private IDbContextFactory dbFactory; + + public SearchService(IDbContextFactory dbFactory) => + this.dbFactory = dbFactory; + + public Media[] Search(string query) { + var db = dbFactory.CreateDbContext(); + + query = query.ToLower(); + + var matchedTag = db.TagDefinitions + .FirstOrDefault(td => td.Name.ToLower() == query)?.Guid; + + Guid[] guids; + + if(matchedTag is not null) { + guids = new[] { (Guid) matchedTag }; + } else { + guids = db.TagDefinitions + .Where(td => td.Name.ToLower().Contains(query)) + .Select(td => td.Guid) + .ToArray(); + } + + return db.Media + .Include(m => m.Tags) + .ThenInclude(m => m.TagDefinition) + .AsEnumerable() + .Where(m => m.Tags.IntersectBy(guids, t => t.TagDefinition.Guid).Any()) + .Concat(db.Media + .Where(m => + (m.ShortDescription != null && m.ShortDescription.ToLower().Contains(query)) || + (m.LongDescription != null && m.LongDescription.ToLower().Contains(query)))) + .DistinctBy(m => m.Guid) + .ToArray(); + } +} diff --git a/_Imports.razor b/_Imports.razor index d20a491..61dd370 100644 --- a/_Imports.razor +++ b/_Imports.razor @@ -1,4 +1,5 @@ -@using HyperBooru +@using BlazorInputFile +@using HyperBooru @using HyperBooru.Pages.Component @using HyperBooru.Services @using Microsoft.AspNetCore.Components.Routing -- cgit v1.3