Commit Graph

535 Commits

Author SHA1 Message Date
89c4bfe13f feat: implement seed-based deterministic random ordering for home page
Replace the fixed GUID-based ordering (OrderBy(a => a.Id)) with a
client-generated seed that produces a truly different random order on
each page refresh. The seed is passed to the server and used to
deterministically shuffle all asset IDs via a hash function, ensuring
consistent pagination with no duplicates across pages within a session.

Also fix LoadPreviousPage showing a spinner when already at page 1 by
adding loadedMinPage <= 1 to the guard clause.
2026-07-08 12:10:37 +02:00
7a0b72584c fix: propagate cancellation tokens through linked child job CTS
Replace manual childJobs.ForEach(j => j.Cancel()) with linked
CancellationTokenSources. Master jobs now call LinkParentToken(token)
on each child, so when the master's CTS fires, all children (running
and queued) receive cancellation automatically via their linked token.

Cancelling a master job now:
- Immediately signals all Running children via their linked CTS
- Ensures queued children, when started by JobManager, receive an
  already-cancelled token and bail without processing
- Eliminates the collection-modification-during-ForEach race condition

Affects: PHashJob, ThumbnailJob, PreviewJob, MetadataJob,
FileSystemCrawlJob.
2026-07-08 12:00:27 +02:00
ebfab19df4 Add autorestart for services 2026-07-08 09:56:45 +02:00
77630f4e83 fix: remove scroll position correction from LoadPreviousPage for smoother scroll-up
The snapshotFirstTileTop/restoreScrollAfterPrepend dance caused a double
visual correction (content shifts down then scroll snaps back) making
scroll-up feel janky compared to scroll-down. Removing it lets new content
naturally push existing tiles down when prepended, matching the expected
scroll-up behavior where content above fills in seamlessly.
2026-07-08 03:40:45 +02:00
16619f9631 feat: add bidirectional infinite scroll (up and down)
- Replace single bottom observer with observeBottom/observeTop dual observers
- Track loadedMinPage/loadedMaxPage to know which pages are in memory
- hasMoreUp flag controls whether scrolling up should load pages
- LoadPreviousPage prepends pages at index 0 with scroll position preservation
  using snapshotFirstTileTop/restoreScrollAfterPrepend JS helpers
- Eviction balanced: scroll down evicts from top, scroll up evicts from bottom
- Both observers registered on first render, methods return early when idle
2026-07-08 03:33:51 +02:00
9829e02a38 fix: download button now fetches blob and triggers actual file download
Previously the download link just navigated cross-origin to the media URL.
Now uses JS interop to fetch the file as a blob, create an object URL,
and trigger a browser download via a hidden anchor element.
2026-07-08 03:27:18 +02:00
632ca0d3e4 feat: add full-size view and download buttons in preview overlay
- Add 'View full size' (opens original in new tab) and 'Download' buttons
- Positioned opposite the cosplayer/album names in the preview info bar
- Info bar always visible so buttons are accessible even without metadata
- Uses original media endpoint with JWT token for authenticated access
2026-07-08 03:24:37 +02:00
4d436620a5 fix: move preview info text below image instead of overlaying on bottom border 2026-07-08 03:16:57 +02:00
78da2b7207 feat: add cosplayer and album name overlays on home page
- Add hover overlay on masonry tiles showing cosplayer and album names
- Add info bar in full-screen preview overlay with same metadata
- Hide overlays entirely when no data is available (jobs not yet run)
- CSS: gradient overlay at tile bottom with smooth fade-in on hover
- CSS: matching info bar at preview bottom
2026-07-08 03:07:06 +02:00
d4a8b272f2 feat: extend AssetPreviewDto with album and cosplayer names
- Add AlbumNames and CosplayerNames fields to AssetPreviewDto
- Include Albums and PersonOwner in AssetRepository.GetAssets() query
- Populate new fields in AssetsMapper.ToAssetPreviewDto()
2026-07-08 03:06:03 +02:00
bb01f6526e fix: remove destructive People soft-delete in IntegrityCheckJob and drop duplicate hash stats 2026-07-08 02:58:00 +02:00
866d01c4e2 fix: rewrite TopTags query to avoid EF Core collection navigation translation error 2026-07-08 02:36:38 +02:00
2159eaec08 fix: populate LastLogin/BannedAt/UpdatedAt in UserInfoDto mapping
UsersMapper.ToGetUsersDto() was not copying LastLogin, BannedAt, or
UpdatedAt from the User entity to the UserInfoDto, causing the client
to always receive null for these fields. Added the missing mappings.

Also added null fallback ('Never') for LastLogin display on the User
page to prevent NullReferenceException when the value has not been set.
2026-07-08 02:32:12 +02:00
bf3e5e619b fix: add JobBatchSize to DefaultSettings.json to prevent reset on restart 2026-07-08 02:25:18 +02:00
REDCODE
458cf70081 feat: add thousands separators to job status numbers 2026-07-08 02:03:40 +02:00
REDCODE
3d81b7a97e fix: skip existing AlbumAsset relationships in CreateAlbumsJob to prevent duplicate key violations on re-run 2026-07-08 01:50:39 +02:00
REDCODE
03f52cfb5b feat: add statistics page with aggregate asset/user/system stats via fast DB queries 2026-07-08 01:49:50 +02:00
REDCODE
4b0a6df5dd fix: per-batch progress messages and counting bug in album/person jobs 2026-07-08 01:30:33 +02:00
REDCODE
744bc9e4d0 feat: improve logging and progress reporting for album/person jobs 2026-07-08 01:23:25 +02:00
REDCODE
76ba4fd74a configuration changes 2026-07-08 01:08:00 +02:00
REDCODE
132e3d2930 fix: make job cancellation work for all job states and types
Job.Cancel() now handles queued jobs (cts null) by setting Canceled status and firing events directly. ContinueWith checks t.IsCanceled to catch ThrowIfCancellationRequested patterns. cts is now disposed after job completion. CreatePersonsJob, CreateAlbumsJob, and IntegrityCheckJob now catch OperationCanceledException and set proper Canceled state. IntegrityCheckJob also gained cancellation checks between each step and within iteration loops.
2026-07-08 01:07:25 +02:00
REDCODE
7554dbac9c fix: cancel past refresh loop when poll rate is set to Off 2026-07-08 01:06:38 +02:00
REDCODE
defd97e7f0 feat: add stacked progress bar for parent jobs with sub-job breakdown
Parent jobs with fetched sub-jobs now show a multi-color stacked
progress bar instead of the single parent-progress bar. Segments
represent sub-job status distribution: completed (success),
running (primary), waiting (info), failed (danger), with-errors
(warning), and queued (primary for visibility in dark theme).

ProgressBar gets an optional Segments parameter for stacked mode.
JobRow accepts Children and computes status-weighted segments.
JobTree passes cached children to JobRow.
2026-07-08 00:20:46 +02:00
REDCODE
6c9a608ce6 fix: propagate cancellation to sub-jobs in batch processing jobs
MetadataJob, ThumbnailJob, PreviewJob, and PHashJob previously only
canceled the master job's own token, leaving already-enqueued sub-jobs
running indefinitely. Added child-job tracking with proper cancellation
propagation at both master cancellation exit points, matching the
existing pattern in FileSystemCrawlJob.
2026-07-08 00:20:40 +02:00
MrFastwind
dc1e44f2be chore(dev): fix ovveride PM Compose deploy 2026-07-07 23:27:57 +02:00
923aaa6865 feat: add CreatePersons and CreateAlbums jobs 2026-07-07 20:33:30 +02:00
53fe2cc3d5 removed unused run configs 2026-07-07 20:05:45 +02:00
970f99db54 fix: wire MaxConcurrentJobs to database setting on startup and runtime changes 2026-07-07 19:56:41 +02:00
96f431fb41 feat: add PreviewJob and upgrade thumbnails to WebP
- Add PreviewJob (WebP) — same master/sub-job pattern as ThumbnailJob
- Convert ThumbnailJob from JPEG to WebP with configurable quality
- Add ThumbnailQuality/PreviewQuality settings (configurable in settings UI)
- Add PreviewSize, ThumbnailFormat, PreviewFormat fields to Asset model
- Add format-aware repo queries for auto-regeneration of stale JPEGs
- Fix MIME types in MediaRepository/MediaController to return image/webp
- Wire PreviewJob into JobScheduler, JobMapper, JobsController
- Expose quality settings on Settings page (Jobs group, range sliders)
- Add 'Make Previews' button on Jobs page, reorder to scan/metadata/thumb/preview/phash/integrity
2026-07-07 19:41:51 +02:00
604f0e33a0 refactor: make LoginService singleton, centralize auth state and persistence
- Register LoginService as singleton in WASM (was scoped)
- Add InitializeAsync() with retry logic for user profile fetch on boot
- LoginService now owns localStorage persistence (not components)
- Login() auto-persists auth and fetches LoggedUser atomically
- Logout() clears localStorage internally
- Reauthenticate() re-fetches LoggedUser if null after token refresh
- Simplify App.razor, Login.razor, NavMenu.razor by removing direct localStorage calls
2026-07-07 19:18:50 +02:00
6d75843dcd feat: make navbar sticky during infinite scroll 2026-07-07 18:43:54 +02:00
0cb5d097d6 update gitignore 2026-07-07 18:38:48 +02:00
0549be6d42 Merge branch 'feature/masonryLayoutInHome' into develop 2026-07-07 18:37:45 +02:00
5cd16a7416 build: upgrade to .NET 10 — packages, Docker images, and Swagger fix
- Bump all NuGet packages to 10.0.x (ASP.NET, EF Core, Npgsql, Swashbuckle)
- Bump Pgvector.EntityFrameworkCore to 0.3.0, Microsoft.IdentityModel.JsonWebTokens to 8.19.1
- Pin Microsoft.OpenApi to 2.7.5, strip security scheme from SwaggerGen (API removed in v2)
- Docker images already at 10.0
2026-07-07 18:25:18 +02:00
5573be1502 Merge remote-tracking branch 'origin/feature/masonryLayoutInHome' into feature/masonryLayoutInHome 2026-07-07 18:09:04 +02:00
99ef2db822 chore: add dotnet-tools.json for ef tool 2026-07-07 18:08:08 +02:00
0502cbbd76 chore: upgrade target framework to net10.0
Update all projects from net8.0 to net10.0 and global.json SDK to 10.0.0.
Gitignore dotnet-tools.json.
2026-07-07 18:03:42 +02:00
6d29f053f4 fix: proper bidirectional SharedWith many-to-many migration
Replace broken one-to-many User.AssetId shadow FK with proper
AssetUser join table using bidirectional navigation:
  HasMany(e => e.SharedWith).WithMany(e => e.SharedAssets)

Join table columns: SharedAssetsId (FK to Assets) + SharedWithId (FK to Users).
Adds SharedAssets navigation to User model.

Generated via dotnet ef migrations add.
2026-07-07 18:03:22 +02:00
MrFastwind
75c667d1c2 Merge remote-tracking branch 'origin/feature/masonryLayoutInHome' into feature/masonryLayoutInHome 2026-07-07 18:02:51 +02:00
MrFastwind
740941790b fix(Lactose): Admin and Curators media visibility 2026-07-07 18:02:29 +02:00
5511bc56f2 fix: remove AspNetCore.SassCompiler to fix Docker startup crash
The native Dart binary at runtimes/linux-x64/src/dart is not
published into the runtime container, causing a crash when the
SassCompilerHostedService tries to start at runtime.

SCSS compilation now must be done manually with the  CLI
or by temporarily re-adding the package. Instructions added
to AGENTS.md.
2026-07-07 17:25:13 +02:00
d90a9421e9 dotnet tools 2026-07-07 17:16:04 +02:00
ba1071ba6c fix: add AssetUser many-to-many join table for SharedWith
Replace broken one-to-many User.AssetId shadow FK with proper
AssetUser join table (AssetsId + SharedWithId composite PK).
Configure explicit UsingEntity in OnModelCreating to match
database column names and prevent convention mismatches.

Migration: 20260707160000_FixSharedWithManyToMany
2026-07-07 17:13:50 +02:00
29b021bee5 feat: pass JWT token in media URLs for authenticated thumbnail/preview requests
- MediaController: accept ?token=<jwt> query param as alt auth for browser img requests,
  validating against signing key via JwtSecurityTokenHandler
- Home.razor: append current JWT token to all thumbnail/preview URLs,
  update on AuthInfoChanged, empty when not logged in
2026-07-07 15:58:56 +02:00
07fcd05031 feat: masonry gallery on homepage with infinite scroll
- Enrich AssetPreviewDto with ResolutionWidth/Height, HasThumbnail, HasPreview
- Extend GET /api/asset with ?type=&random=true for gallery queries
- Add general GetAssets repository method (type, dates, random, pagination)
- Fix LactoseAuthService.GetUserData to handle unmapped JWT claim names
- Add request-level auth debug logging middleware
- New AssetService (MilkStream.Client) for gallery API calls
- Rewrite Home.razor: CSS column-count masonry, infinite scroll via
  IntersectionObserver JS interop, inline preview overlay with
  progressive loading (preview -> thumbnail fallback), arrow/Esc nav
- Home.razor.css: responsive 2-5 column masonry, overlay styles,
  content-visibility:auto for memory optimization
- Sliding window of 10 pages (300 tiles) with loading=lazy images
- Broken thumbnail fallback to Bootstrap bi-image icon
2026-07-07 15:44:03 +02:00
64a0fdf81d feat(folders): add regex pattern field with named groups, syntax highlighting, and sample path preview 2026-07-07 14:19:35 +02:00
9e8723b79f feat(settings): add runtime-configurable Po2W slider limits + split thumbnail/preview ranges
- SettingRange.razor: add MinPowerValue/MaxPowerValue params; component computes
  log2 exponents internally when set, falls back to MinValue/MaxValue for
  non-Po2W sliders (TimePicker)
- Settings.razor: Po2W case passes pixel values via MinPowerValue/MaxPowerValue
  instead of exponents; move Thumbnail Size and Preview Size to Jobs tab
- DefaultSettings.json: Thumbnail 64-1024 px, Preview 256-4096 px (split ranges)
- Migration: ConvertPo2WOptionsToPixelValues — converts existing Po2W Options
  from exponents to actual pixel values via POWER(2,n), guarded by < 32 check
  to skip already-migrated rows
2026-07-07 13:07:11 +02:00
1ecd6d167a fix: add DeletedAt filter to asset batch queries to exclude soft-deleted assets 2026-07-07 12:13:39 +02:00
78ecec2e12 fix(jobs): add delay to JobManager main loop to prevent CPU spin 2026-07-07 12:13:01 +02:00
6ac692f137 fix(jobs): fix IntegrityCheckJob conditional + use soft-delete 2026-07-07 12:12:15 +02:00