blob: 948d135eb58a894942d26157ade583d025710728 (
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
|
@page "/"
@page "/Gallery"
@inject IDbContextFactory<HBContext> dbFactory
@inject ITagService tagService
@inject IFeedService feedService
@inject ISearchService searchService
@inject IUserService userService
@inject IJSRuntime jsRuntime
@implements IDisposable
@attribute [Authorize]
<PageTitle>@Title</PageTitle>
@if(Ingest && !userService.ShowNsfw) {
<div id="ingest-warning">
<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>
<div id="canary"/>
<script suppress-error="BL9992">
function registerScrollObserver(dotNetObject) {
var scrollObserver = new IntersectionObserver(
async (e) => {
if(e[0].isIntersecting) {
await dotNetObject.invokeMethodAsync('LoadMore');
}
},
{ threshold: [1] });
scrollObserver.observe(document.getElementById("canary"));
}
</script>
@code {
[Parameter]
[SupplyParameterFromQuery(Name = "q")]
public string? Query { get; set; }
[Parameter]
[SupplyParameterFromQuery]
public bool Ingest { get; set; } = false;
public const int PageSize = 50;
private string Title {
get {
if(Query is null)
return Ingest ? "Ingest Feed" : "Gallery";
else
return "Search Results";
}
}
private List<Media> displayMedia;
private Media[] queryResult;
private IEnumerator<Media> mediaEnumerator;
private FeedOptions feedOptions = new() {
SortType = FeedSortType.Chronological,
SortOrder = FeedSortOrder.Descending,
RandomPosition = false,
IncludeProperties = (media) => media
.Include(m => m.Tags)
.Include(m => m.CurrentUploadedFile)
};
protected override void OnInitialized() =>
userService.ShowNsfwChanged += ShowNsfwChanged;
protected override void OnParametersSet() => LoadMedia();
protected override void OnAfterRender(bool firstRender) {
if(firstRender)
jsRuntime.InvokeVoidAsync(
"registerScrollObserver",
DotNetObjectReference.Create(this));
}
private void LoadMedia() {
feedService.InitializeFeed(feedOptions);
using var db = dbFactory.CreateDbContext();
if(Query is not null) {
queryResult = searchService.Search(Query)
.OrderByDescending(m => m.ObjectId)
.ToArray();
} else {
queryResult = db.Media
.Include(m => m.Tags)
.Include(m => m.CurrentUploadedFile)
.OrderByDescending(m => m.ObjectId)
.ToArray();
}
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(HBObjectGuid.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.ShowNsfw)
if(m.Tags.Select(t => t.TagDefinitionId).Intersect(nsfwTags).Any() || m.IsIngest)
continue;
if(m.IsIngest != Ingest)
continue;
yield return m;
}
}
private async void ShowNsfwChanged(object? sender, bool showNsfw) {
await InvokeAsync(() => {
LoadMedia();
StateHasChanged();
});
}
public void Dispose() {
mediaEnumerator.Dispose();
userService.ShowNsfwChanged -= ShowNsfwChanged;
}
}
|