summaryrefslogtreecommitdiff
path: root/Services/SearchService.cs
blob: 7c677b2970a532bb0c9c076b97f2eca3f332bdd7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
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();

        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();
    }
}