diff options
| author | Jake Mannens <jake@asger.xyz> | 2026-03-25 01:57:19 +1100 |
|---|---|---|
| committer | Jake Mannens <jake@asger.xyz> | 2026-03-25 01:57:46 +1100 |
| commit | 6c06dfc4f83f30292e65c08a3cb0c48401d4bfa7 (patch) | |
| tree | 511f88873fa6173637115a38c31ec5f8018e108e | |
| parent | c751709b1b4fe6f16fd84647e8e071455e7b78d6 (diff) | |
v0.2av0.2a
| -rw-r--r-- | Controllers/MediaController.cs | 2 | ||||
| -rw-r--r-- | Exception.cs | 10 | ||||
| -rw-r--r-- | Pages/Component/MediaTagTable.razor | 2 | ||||
| -rw-r--r-- | Pages/Gallery.razor | 131 | ||||
| -rw-r--r-- | Pages/Gallery.razor.css | 2 | ||||
| -rw-r--r-- | Pages/TagDefinitions.razor | 2 | ||||
| -rw-r--r-- | Program.cs | 2 | ||||
| -rw-r--r-- | Server.csproj | 6 | ||||
| -rw-r--r-- | Services/ConfigService.cs | 4 | ||||
| -rw-r--r-- | Services/FeedService.cs | 155 | ||||
| -rw-r--r-- | Services/MediaService.cs | 75 | ||||
| -rw-r--r-- | Services/OcrService.cs | 18 | ||||
| -rw-r--r-- | Services/SearchService.cs | 117 |
13 files changed, 280 insertions, 246 deletions
diff --git a/Controllers/MediaController.cs b/Controllers/MediaController.cs index 3368f45..2c015f7 100644 --- a/Controllers/MediaController.cs +++ b/Controllers/MediaController.cs @@ -32,7 +32,7 @@ public class MediaController : Controller { var fs = System.IO.File.OpenRead(mediaService.GetPath(media)); - return new FileStreamResult(fs, media.CurrentUploadedFile.MimeType); + return new FileStreamResult(fs, media.CurrentUploadedFile!.MimeType); } [HttpGet("thumb/{mediaId}")] diff --git a/Exception.cs b/Exception.cs index 1e070eb..fc3feda 100644 --- a/Exception.cs +++ b/Exception.cs @@ -47,11 +47,13 @@ public class TagDuplicateException : TagException { } public class MediaException : HBException { - public Media? Media { get; private init; } + public Guid? MediaId { get; private init; } = null; public MediaException(string message) : base(message) {} + public MediaException(string message, Guid mediaId) : base(message) => + MediaId = mediaId; public MediaException(string message, Media media) : base(message) => - Media = media; + MediaId = media.Guid; } public class MediaCreateException : MediaException { @@ -60,6 +62,8 @@ public class MediaCreateException : MediaException { } public class ThumbnailException : MediaException { + public ThumbnailException(string message, Guid mediaId) + : base(message, mediaId) {} public ThumbnailException(string message, Media media) - :base(message, media) {} + : base(message, media) {} } diff --git a/Pages/Component/MediaTagTable.razor b/Pages/Component/MediaTagTable.razor index e367f7f..e687529 100644 --- a/Pages/Component/MediaTagTable.razor +++ b/Pages/Component/MediaTagTable.razor @@ -19,7 +19,7 @@ } </td> <td> - <a href="/Gallery?q=@(e.tagDef.Name)" class="nondecorated"> + <a href="/Gallery?t=@(e.tagDef.Guid)" class="nondecorated"> @if(e.isImplicit) { <i>@e.tagDef.Name</i> } else { diff --git a/Pages/Gallery.razor b/Pages/Gallery.razor index 762ef7f..c037979 100644 --- a/Pages/Gallery.razor +++ b/Pages/Gallery.razor @@ -1,8 +1,7 @@ @page "/" @page "/Gallery" -@inject IDbContextFactory<HBContext> dbFactory @inject ITagService tagService -@inject ISearchService searchService +@inject IFeedService feedService @inject IUserService userService @inject IJSRuntime jsRuntime @implements IDisposable @@ -11,31 +10,36 @@ <PageTitle>@Title</PageTitle> @if(Ingest && !userService.UserSessionState.ShowNsfw) { - <div id="ingest-warning"> + <div id="feed-error"> <p><center>Ingest feed is not available unless NSFW mode is enabled!</center></p> <p><center><i>You must enable NSFW mode to continue...</i></center></p> </div> -} - -<div style="padding:var(--size-default-gap);"> - @foreach(var media in displayMedia) { - // Precalculate thumbnail size to help the browser - // lay out the images during initial page load - int width = (int) media.CurrentUploadedFile.Width! * 200 / (int) media.CurrentUploadedFile.Height!; - <a href="/ViewMedia?m=@(media.Guid)"> - <img src="/media/thumb/@(media.Guid)?h=200" width=@width height="200"/> - </a> - } -</div> +} else if(TagId is not null && Query is not null) { + <div id="feed-error"> + <p><center>Invalid query parameters! Both a search query and</center></p> + <p><center>a tag ID have been specified!</center></p> + </div> +} else { + <div style="padding:var(--size-default-gap);"> + @foreach(var media in displayMedia) { + // Precalculate thumbnail size to help the browser + // lay out the images during initial page load + int width = (int) media.CurrentUploadedFile!.Width! * 200 / (int) media.CurrentUploadedFile.Height!; + <a href="/ViewMedia?m=@(media.Guid)"> + <img src="/media/thumb/@(media.Guid)?h=200" width=@width height="200"/> + </a> + } + </div> -<div id="canary"/> + <div id="canary"/> +} <script suppress-error="BL9992"> function registerScrollObserver(dotNetObject) { var scrollObserver = new IntersectionObserver( async (e) => { if(e[0].isIntersecting) { - await dotNetObject.invokeMethodAsync('LoadMore'); + await dotNetObject.invokeMethodAsync('LoadMedia', false); } }, { threshold: [1] }); @@ -45,6 +49,10 @@ @code { [Parameter] + [SupplyParameterFromQuery(Name = "t")] + public Guid? TagId { get; set; } + + [Parameter] [SupplyParameterFromQuery(Name = "q")] public string? Query { get; set; } @@ -64,13 +72,11 @@ } private List<Media> displayMedia; - private Media[] queryResult; - private IEnumerator<Media> mediaEnumerator; protected override void OnInitialized() => userService.UserSessionState.OnStateChange += ShowNsfwChanged; - protected override void OnParametersSet() => LoadMedia(); + protected override void OnParametersSet() => LoadMedia(true); protected override void OnAfterRender(bool firstRender) { if(firstRender) @@ -79,71 +85,44 @@ DotNetObjectReference.Create(this)); } - private void LoadMedia() { - using var db = dbFactory.CreateDbContext(); + [JSInvokable("LoadMedia")] + public void LoadMedia(bool initial = false) { + Media? key = displayMedia?.Any() ?? false && !initial ? displayMedia.Last() : null; + + if(initial) + displayMedia = new(); - if(Query is not null) { - queryResult = searchService.Search(Query) - .OrderByDescending(m => m.ObjectId) - .ToArray(); + if(TagId is not null && Query is null) { + displayMedia!.AddRange(feedService.LoadChunk( + selectIngest: Ingest, + includeNsfw: userService.UserSessionState.ShowNsfw, + tagId: (Guid) TagId!, + key: key, + count: PageSize)); + } else if(Query is not null && TagId is null) { + displayMedia!.AddRange(feedService.LoadChunk( + selectIngest: Ingest, + includeNsfw: userService.UserSessionState.ShowNsfw, + query: string.IsNullOrWhiteSpace(Query) ? null : Query, + key: key, + count: PageSize)); } else { - queryResult = db.Media - .Include(m => m.Tags) - .Include(m => m.CurrentUploadedFile) - .OrderByDescending(m => m.ObjectId) - .ToArray(); + displayMedia!.AddRange(feedService.LoadChunk( + selectIngest: Ingest, + includeNsfw: userService.UserSessionState.ShowNsfw, + key: key, + count: PageSize)); } - mediaEnumerator = FilterMedia(queryResult).GetEnumerator(); - - displayMedia = new(); - - LoadMore(); - } - - [JSInvokable("LoadMore")] - public void LoadMore() { - for(int i = 0; i < PageSize; i++) { - if(!mediaEnumerator.MoveNext()) - break; - displayMedia.Add(mediaEnumerator.Current); - } - StateHasChanged(); - } - - private IEnumerable<Media> FilterMedia(IEnumerable<Media> media) { - var nsfwTags = tagService.TagsThatImply(HBContext.NsfwTag) - .Select(td => td.ObjectId) - .ToArray(); - - using var enumerator = media.GetEnumerator(); - - while(true) { - bool success = enumerator.MoveNext(); - if(!success) - break; - Media? m = enumerator.Current; - - if(!userService.UserSessionState.ShowNsfw) - if(m.Tags.Select(t => t.TagDefinitionId).Intersect(nsfwTags).Any() || m.IsIngest) - continue; - - if(m.IsIngest != Ingest) - continue; - - yield return m; - } + StateHasChanged(); } private async void ShowNsfwChanged(UserSessionState userSessionState) { await InvokeAsync(() => { - LoadMedia(); - StateHasChanged(); + LoadMedia(true); }); } - public void Dispose() { - mediaEnumerator.Dispose(); - userService.UserSessionState.OnStateChange -= ShowNsfwChanged; - } + public void Dispose() => + userService.UserSessionState.OnStateChange -= ShowNsfwChanged; } diff --git a/Pages/Gallery.razor.css b/Pages/Gallery.razor.css index 0e01e0e..989e252 100644 --- a/Pages/Gallery.razor.css +++ b/Pages/Gallery.razor.css @@ -3,7 +3,7 @@ max-height: 200px; } -div#ingest-warning { +div#feed-error { position: relative; top: 50%; left: 50%; diff --git a/Pages/TagDefinitions.razor b/Pages/TagDefinitions.razor index e2e4df6..f3dca0f 100644 --- a/Pages/TagDefinitions.razor +++ b/Pages/TagDefinitions.razor @@ -26,7 +26,7 @@ <tr data-guid="@tagDef.Guid"> <td>@tagDef.Alias</td> <td> - <a href="/Gallery?q=@tagDef.Name" class="nondecorated"> + <a href="/Gallery?t=@tagDef.Guid" class="nondecorated"> @tagDef.Name </a> </td> @@ -22,7 +22,7 @@ public class Program { // Add our custom services builder.Services.AddSingleton<IConfigService, ConfigService>(); builder.Services.AddDbContextFactory<HBContext>(); - builder.Services.AddScoped<ISearchService, SearchService>(); + builder.Services.AddScoped<IFeedService, FeedService>(); builder.Services.AddScoped<ITagService, TagService>(); builder.Services.AddScoped<IMediaService, MediaService>(); builder.Services.AddSingleton<IGlobalUserService, GlobalUserService>(); diff --git a/Server.csproj b/Server.csproj index e3ca595..7ce894a 100644 --- a/Server.csproj +++ b/Server.csproj @@ -6,9 +6,9 @@ <ImplicitUsings>enable</ImplicitUsings> <AssemblyName>HyperBooru</AssemblyName> <RootNamespace>HyperBooru</RootNamespace> - <AssemblyVersion>0.1.0.0</AssemblyVersion> + <AssemblyVersion>0.2.0.0</AssemblyVersion> <FileVersion>$(AssemblyVersion)</FileVersion> - <Version>0.1-alpha</Version> + <Version>0.2-alpha</Version> <UserSecretsId>2907567f-4640-4581-8f4d-0977952d26bd</UserSecretsId> </PropertyGroup> @@ -21,7 +21,7 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="Magick.NET-Q16-AnyCPU" Version="14.10.2" /> + <PackageReference Include="Magick.NET-Q16-AnyCPU" Version="14.10.4" /> <PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.23" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.23"> <PrivateAssets>all</PrivateAssets> diff --git a/Services/ConfigService.cs b/Services/ConfigService.cs index b42b80c..8460fd0 100644 --- a/Services/ConfigService.cs +++ b/Services/ConfigService.cs @@ -5,6 +5,7 @@ public interface IConfigService { public string DbConnectionString { get; } public string MediaBasePath { get; } public string ThumbnailBasePath { get; } + public bool EnableOcr { get; } } public class ConfigService : IConfigService { @@ -46,6 +47,9 @@ public class ConfigService : IConfigService { public string ThumbnailBasePath => Path.Join(DataPath, "thumb"); + public bool EnableOcr => + bool.TryParse(config["DisableOcr"], out bool x) ? !x : true; + public ConfigService(IConfiguration config) { this.config = config; InitDirectoryStructure(); diff --git a/Services/FeedService.cs b/Services/FeedService.cs new file mode 100644 index 0000000..864a751 --- /dev/null +++ b/Services/FeedService.cs @@ -0,0 +1,155 @@ +using Microsoft.EntityFrameworkCore; + +namespace HyperBooru.Services; + +public interface IFeedService { + public Media[] LoadChunk( + bool selectIngest, + bool includeNsfw, + Media? key = null, + int count = 50); + + public Media[] LoadChunk( + bool selectIngest, + bool includeNsfw, + string query, + Media? key = null, + int count = 50); + + public Media[] LoadChunk( + bool selectIngest, + bool includeNsfw, + Guid tagId, + Media? key = null, + int count = 50); +} + +public class FeedService : IFeedService { + private IDbContextFactory<HBContext> dbFactory; + + public FeedService(IDbContextFactory<HBContext> dbFactory) => + this.dbFactory = dbFactory; + + public Media[] LoadChunk( + bool selectIngest, + bool includeNsfw, + Media? key, + int count) => LoadChunkInternal(selectIngest, includeNsfw, null, null, key, count); + + public Media[] LoadChunk( + bool selectIngest, + bool includeNsfw, + string query, + Media? key, + int count) => LoadChunkInternal(selectIngest, includeNsfw, query, null, key, count); + + public Media[] LoadChunk( + bool selectIngest, + bool includeNsfw, + Guid tagId, + Media? key, + int count) => LoadChunkInternal(selectIngest, includeNsfw, null, tagId, key, count); + + private Media[] LoadChunkInternal( + bool selectIngest, + bool includeNsfw, + string? query, + Guid? tagId, + Media? key, + int count) { + + if(selectIngest && !includeNsfw) + return Array.Empty<Media>(); + + using var db = dbFactory.CreateDbContext(); + + IQueryable<Media> media = db.Media + .AsSingleQuery() + .AsNoTracking() + .Include(m => m.Tags) + .Include(m => m.CurrentUploadedFile); + + if(!includeNsfw) + media = media + .Where(m => !TagsThatImply(db, HBContext.NsfwTag) + .Intersect(m.Tags.Select(t => t.TagDefinitionId)) + .Any()); + + if(selectIngest) { + media = media + .Where(m => m.Tags + .Select(t => t.TagDefinitionId) + .Contains((int) HBObjectId.IngestTag)); + } else { + media = media + .Where(m => !m.Tags + .Select(t => t.TagDefinitionId) + .Contains((int) HBObjectId.IngestTag)); + } + + if(query is not null) { + media = Search(media, query); + } else if(tagId is not null) { + media = media + .Where(m => TagsThatImply(db, (Guid) tagId) + .Intersect(m.Tags.Select(t => t.TagDefinitionId)) + .Any()); + } + + if(key is not null) + media = media.Where(m => m.ObjectId > key.ObjectId); + + return media + .OrderBy(m => m.ObjectId) + .Take(count) + .ToArray(); + } + + private static IQueryable<Media> Search(IQueryable<Media> media, string query) { + // TODO: search implicit tags as well + + query = query.ToLower().Trim(); + + return media + .Where(m => + (m.ShortDescription != null && m.ShortDescription.ToLower().Contains(query)) || + (m.LongDescription != null && m.LongDescription.ToLower().Contains(query)) || + (m.UploadedFiles.Any(uf => uf.Filename != null && uf.Filename.ToLower().Contains(query))) || + (m.OcrData != null && m.OcrData.SearchableText.ToLower().Contains(query)) || + (m.Tags.Any(t => t.TagDefinition.Name.ToLower().Contains(query)))); + } + + private static IQueryable<int> TagsThatImply(HBContext db, Guid tagId) => + db.Database.SqlQueryRaw<int>(""" + WITH RECURSIVE basetag AS ( + SELECT "ObjectId" FROM "Objects" WHERE "Guid" = {0} + ), + impliedtags AS ( + SELECT + "TagDefinitionObjectId" + FROM + "TagDefinitionTagDefinition" + INNER JOIN + basetag + ON + "ImplicitTagsObjectId" = basetag."ObjectId" + UNION + SELECT + "TagDefinitionTagDefinition"."TagDefinitionObjectId" + FROM + "TagDefinitionTagDefinition" + INNER JOIN + impliedtags + ON + impliedtags."TagDefinitionObjectId" = "TagDefinitionTagDefinition"."ImplicitTagsObjectId" + ) + SELECT DISTINCT + "TagDefinitionObjectId" AS "Value" + FROM impliedtags + UNION + SELECT + "ObjectId" AS "Value" + FROM + basetag + """, tagId); +} diff --git a/Services/MediaService.cs b/Services/MediaService.cs index 104d0db..a5803f9 100644 --- a/Services/MediaService.cs +++ b/Services/MediaService.cs @@ -31,8 +31,10 @@ public interface IMediaService { public void DeleteThumbnails(Media media); public Stream GetThumbnail(Guid media, int? width, int? height); public Stream GetThumbnail(Media media, int? width, int? height); + public string GetPath(Guid media); + public string GetPath(Guid media, int? width, int? height); public string GetPath(Media media); - public string GetPath(Media media, int width, int height); + public string GetPath(Media media, int? width, int? height); } @@ -259,37 +261,29 @@ public class MediaService : IMediaService { public void DeleteThumbnails(Media media) => DeleteThumbnails(media.Guid); - public Stream GetThumbnail(Guid media, int? width, int? height) { - using var db = dbFactory.CreateDbContext(); + public Stream GetThumbnail(Guid mediaId, int? width, int? height) { + if(width is null && height is null) + throw new ThumbnailException( + "Both width and height cannot be null!", + mediaId); - var m = db.Media - .Include(m => m.CurrentUploadedFile) - .First(m => m.Guid == media); - if(m is null) - throw new ObjectNotFoundException(media); + var thumbPath = GetPath(mediaId, width, height); - if(m.CurrentUploadedFile.MimeType.Split("/")[0] != "image") - throw new ThumbnailException("Media object not an image", m); + if(File.Exists(thumbPath)) + return System.IO.File.OpenRead(thumbPath); - using var image = new MagickImage(GetPath(m)); + if(!File.Exists(GetPath(mediaId))) + throw new ObjectNotFoundException(mediaId); - if(width is null && height is null) - throw new ThumbnailException("Both width and height cannot be null!", m); + using var image = new MagickImage(GetPath(mediaId)); if(width > image.Width || height > image.Height) - throw new ThumbnailException("Requested thumbnail size is larger than original media", m); - - #pragma warning disable CS8629 - int w = (int) (width is not null ? width : image.Width * height / image.Height); - int h = (int) (height is not null ? height : image.Height * width / image.Width); - #pragma warning restore CS8629 - - var thumbPath = GetPath(m, w, h); + throw new ThumbnailException( + "Requested thumbnail size is larger than original media", + mediaId); - if(!File.Exists(thumbPath)) { - image.Resize((uint) w, (uint) h); - image.Write(thumbPath); - } + image.Thumbnail((uint) (width ?? -1), (uint) (height ?? -1)); + image.Write(thumbPath, MagickFormat.Jpeg); return System.IO.File.OpenRead(thumbPath); } @@ -297,29 +291,40 @@ public class MediaService : IMediaService { public Stream GetThumbnail(Media media, int? width, int? height) => GetThumbnail(media.Guid, width, height); - public string GetPath(Media media) { + public string GetPath(Guid mediaId) { var fileInfo = new FileInfo( Path.Join( config.MediaBasePath, - media.Guid.ToString().Substring(0, 2), - media.Guid.ToString().Substring(2, 2), - media.Guid.ToString())); + mediaId.ToString().Substring(0, 2), + mediaId.ToString().Substring(2, 2), + mediaId.ToString())); - Directory.CreateDirectory(fileInfo.Directory.FullName); + Directory.CreateDirectory(fileInfo.Directory!.FullName); return fileInfo.FullName; } - public string GetPath(Media media, int width, int height) { + public string GetPath(Guid mediaId, int? width, int? height) { + if(width is null && height is null) + throw new ThumbnailException( + "Both width and height cannot be null!", + mediaId); + var fileInfo = new FileInfo(Path.Join( config.ThumbnailBasePath, - media.Guid.ToString().Substring(0, 2), - media.Guid.ToString().Substring(2, 2), - $"{media.Guid.ToString()}-{width}-{height}")); + mediaId.ToString().Substring(0, 2), + mediaId.ToString().Substring(2, 2), + $"{mediaId.ToString()}-{(width ?? 0)}-{(height ?? 0)}")); - Directory.CreateDirectory(fileInfo.Directory.FullName); + Directory.CreateDirectory(fileInfo.Directory!.FullName); return fileInfo.FullName; } + public string GetPath(Media media) => + GetPath(media.Guid); + + public string GetPath(Media media, int? width, int? height) => + GetPath(media.Guid, width, height); + private int GetUploadedFileHash(UploadedFile uf) => ( uf.CreateTime, uf.LastWriteTime, diff --git a/Services/OcrService.cs b/Services/OcrService.cs index 4d21705..40905aa 100644 --- a/Services/OcrService.cs +++ b/Services/OcrService.cs @@ -18,18 +18,21 @@ public class OcrService : IHostedService { private Timer timer; + private IConfigService configService; private IServiceScopeFactory scopeFactory; private ILogger<OcrService> logger; private IDbContextFactory<HBContext> dbFactory; public OcrService( + IConfigService configService, IServiceScopeFactory scopeFactory, ILogger<OcrService> logger, IDbContextFactory<HBContext> dbFactory) { - this.scopeFactory = scopeFactory; - this.logger = logger; - this.dbFactory = dbFactory; + this.configService = configService; + this.scopeFactory = scopeFactory; + this.logger = logger; + this.dbFactory = dbFactory; timer = new((object? state) => { if(task is not null && !task.IsCompleted) @@ -40,8 +43,11 @@ public class OcrService : IHostedService { } public Task StartAsync(CancellationToken ct) { - logger.LogInformation("Service starting..."); - timer.Change(StartupDelay, ProcessInterval); + if(configService.EnableOcr) { + logger.LogInformation("Service starting..."); + timer.Change(StartupDelay, ProcessInterval); + } + return Task.CompletedTask; } @@ -53,8 +59,6 @@ public class OcrService : IHostedService { } async Task ProcessAllAsync(CancellationToken ct) { - return; - using var scope = scopeFactory.CreateScope(); var mediaService = scope.ServiceProvider .GetRequiredService<IMediaService>(); diff --git a/Services/SearchService.cs b/Services/SearchService.cs deleted file mode 100644 index 5ca12e1..0000000 --- a/Services/SearchService.cs +++ /dev/null @@ -1,117 +0,0 @@ -using Microsoft.EntityFrameworkCore; - -namespace HyperBooru.Services; - -public interface ISearchService { - public Media[] Search(string query); -} - -public class SearchService : ISearchService { - private ITagService tagService; - - private IDbContextFactory<HBContext> dbFactory; - - public SearchService( - IDbContextFactory<HBContext> dbFactory, - ITagService tagService) { - - this.tagService = tagService; - this.dbFactory = dbFactory; - } - - public Media[] Search(string query) { - var db = dbFactory.CreateDbContext(); - - query = query.ToLower().Trim(); - - int[] descriptionResults = SearchDescription(query); - int[] filenameResults = SearchFilenames(query); - int[] ocrResults = SearchOcr(query); - - var matchedTag = db.TagDefinitions - .FirstOrDefault(td => td.Name.ToLower() == query); - - int[] tags; - if(matchedTag is not null) { - tags = tagService - .TagsThatImply(matchedTag) - .Select(td => td.ObjectId) - .ToArray(); - } else { - // TODO: Expand scope to all tags that imply - tags = db.TagDefinitions - .Where(td => td.Name.ToLower().Contains(query)) - .Select(td => td.ObjectId) - .ToArray(); - } - - int[] tagResults = SearchTags(tags); - - int[] mediaIds = descriptionResults - .Union(filenameResults) - .Union(ocrResults) - .Union(tagResults) - .OrderDescending() - .ToArray(); - - return db.Media - .Include(m => m.Tags) - .Include(m => m.CurrentUploadedFile) - .Where(m => mediaIds.Contains(m.ObjectId)) - .ToArray(); - } - - // TODO: Make asynchronous - private int[] SearchDescription(string query) { - return Task.Run(() => { - using var db = dbFactory.CreateDbContext(); - query = query.ToLower(); - return db.Media - .Where(m => - (m.ShortDescription != null && m.ShortDescription.ToLower().Contains(query)) || - (m.LongDescription != null && m.LongDescription.ToLower().Contains(query))) - .Select(m => m.ObjectId) - .ToArray(); - }).GetAwaiter().GetResult(); - } - - // TODO: Make asynchronous - private int[] SearchFilenames(string query) { - return Task.Run(() => { - using var db = dbFactory.CreateDbContext(); - query = query.ToLower(); - return db.UploadedFiles - .Include(uf => uf.Media) - .Where(uf => uf.Filename != null && uf.Filename.ToLower().Contains(query)) - .Select(uf => uf.Media.ObjectId) - .Distinct() - .ToArray(); - }).GetAwaiter().GetResult(); - } - - // TODO: Make asynchronous - private int[] SearchOcr(string query) { - return Task.Run(() => { - using var db = dbFactory.CreateDbContext(); - query = query.ToLower(); - return db.OcrData - .Include(o => o.Media) - .Where(o => o.SearchableText.Contains(query)) - .Select(o => o.Media.ObjectId) - .ToArray(); - }).GetAwaiter().GetResult(); - } - - // TODO: Make asynchronous - private int[] SearchTags(int[] tags) { - return Task.Run(() => { - using var db = dbFactory.CreateDbContext(); - return db.Media - .Include(m => m.Tags) - .AsEnumerable() - .Where(m => m.Tags.IntersectBy(tags, t => t.TagDefinitionId).Any()) - .Select(m => m.ObjectId) - .ToArray(); - }).GetAwaiter().GetResult(); - } -} |
