Commit Graph
11 Commits
Author SHA1 Message Date
JakeBreath b71ec729e0 Enrich IQDB candidates; link downloads the e621 original
- IQDB responses carry no preview/file data, so candidates only showed an
  ID; the SPA now enriches them with one batched posts lookup (preview,
  rating, score, favourites, dimensions, tag preview)
- Candidate tiles are selectable instead of instantly resolving: picking
  one shows its info and an explicit 'Link selected post' button
- Linking a post now fetches the e621 original into the library and
  drops the staged upload; when the staged file's MD5 already equals the
  post's file, the staged copy is moved instead (identical bytes)
- Keep the file URL in stored e621 metadata; sanitize the new candidate
  fields server-side
2026-09-17 11:24:01 -05:00
JakeBreath 7deb6084b6 Fix staged upload previews and allow WebP
- Staged files are now served through a signed URL (Django signing, 24h)
  so <img>/<video> tags can load previews without an Authorization
  header; the file endpoint accepts header auth or a valid signature,
  rejects tampered signatures, and still scopes access to the owner
- Serializer responses now carry the request context so URLs are signed
  per user
- Add .webp to the allowed extensions (backend + upload hint)
2026-09-17 11:17:04 -05:00
JakeBreath d0e2901c92 Upload pipeline: staging, MD5 auto-match, IQDB, three-column board
Backend:
- TempUpload model: staged files (pending / visual_match / completed /
  error) with resolution, e621 payload, custom metadata and IQDB data
- Files land in a temp folder and only move into the watched library
  folder once resolved; duplicates resolve immediately without a copy
- Endpoints: stage (multipart), list, retrieve, temp file, IQDB save,
  resolve (link to post or custom metadata), discard/dismiss
- cleanup_temp_uploads command for old staged files
- Replaces the old direct-to-library upload endpoint

Frontend:
- Upload page is now a three-column board (Pending & Unmatched /
  Visual Similarity Detected / Auto-uploaded & Indexed)
- After upload: MD5s are batch-checked against e621 and matches
  auto-complete with full post metadata; remaining files run through
  IQDB and move to the similarity column when candidates exist
- Metadata modal with IQDB candidates, post-ID linking and custom
  tags/rating/notes; discard and dismiss actions
- e621 client gains fetchPostsByMd5 and iqdbSearch helpers

Roadmap updated with the completed upload items.
2026-09-17 11:12:03 -05:00
JakeBreath ebac3ac922 Keep e621 metadata on downloaded posts; clear up account roles
Roles:
- JakeBreathild is now staff + superuser (the real account); the 'jake'
  smoke-test account was demoted to a regular user
- /me exposes is_superuser and the account page shows an admin badge

e621 metadata:
- MediaItem gains e621_post_id and e621_data (trimmed post payload:
  tags by category, rating, score, favourites, comments, sources,
  description, pools, relationships, file info, uploader)
- Download to Library accepts the post payload from the SPA and stores
  it; the item's custom rating is seeded from the e621 rating when empty
- Library detail shows an e621 metadata card: link to the in-app post,
  score/favourites/comments, taxonomy-coloured tags, DText description,
  sources and pools; grid cards get an e621 badge and fall back to the
  e621 rating for their colour (display_rating)
- Guest visibility now also considers e621 tags, so downloaded explicit
  content is hidden from anonymous visitors
2026-09-17 10:27:06 -05:00
JakeBreath e5cc63b0cc Phase 3: J-IDs, ownership, roles, guest safety, adaptive detail, download
Backend:
- User.role (user/uploader/staff) with can_upload; uploads and downloads
  gated to uploader+; owners and staff can edit their items
- MediaItem.uploaded_by plus J-<id> identity (serializer, admin,
  scan_files --user, first superuser as default owner)
- API resolves J-<id>, bare numeric ids and MD5s; neighbors and lookup
  return j_ids
- Guest safety: mirror e621's anonymous default blacklist into Redis
  (parses comments, negations and wildcards), flag hidden_from_guests
  and filter lists, details and lookups for anonymous users
- POST /api/online/downloads/ writes an e621 file into the watched
  folder and indexes it for the uploader
- MariaDB + Redis via docker compose (host ports 3307/6380), PyMySQL
  driver shim, Redis cache replacing the file cache; SQLite data
  dumped and loaded into MariaDB

Frontend:
- Single /detail/:itemId route with an adaptive shell: J-<id> renders
  the library item, bare numbers render the e621 post
- Legacy /view/<md5> and /online/view/<id> redirect to canonical URLs
- Cards expose J-IDs; library custom-data editor is read-only for
  non-owners
- Role gating: Upload hidden/blocked for regular users, account shows
  the role, guest hint on the library
2026-09-17 10:16:45 -05:00
JakeBreath 04448bf615 Online browser + post detail: SPA talks to e621 directly
Backend:
- POST /api/files/lookup/ reports which MD5s are already in the library

Frontend:
- e621 client extended with post/tag/favorite types and helpers: post
  search, post detail, batch posts by id, tag autocomplete, toggle
  favorite
- /online: tag search with autocomplete, post grid with rating colors
  and in-library badges, numbered pagination, page tag cloud, blacklist
  panel and filtered counts from /users/me.json, anonymous hint
- /online/view/🆔 media viewer (sample or original, video support),
  taxonomy-colored tags by category, specs sheet, favorite/unfavorite,
  description, sources, pools and parent/children thumbnails
- Shared CollapsibleSidebar extracted from the library page; Online
  added to the nav, command palette and sidebar toggle
2026-09-17 09:00:17 -05:00
JakeBreath b6409523e6 e621 credentials: user fields, API endpoint, Account screen
Backend:
- User model gains e621_username / e621_api_key / e621_base_url
- GET/PUT /api/auth/e621/ for the owner's credentials; /me exposes only
  the username and a configured flag, never the key

Frontend:
- e621 client core: Basic auth, _client param (browsers cannot set a
  User-Agent), serialized queue throttled to 1 request/second, readable
  error mapping
- Account screen (/account): username, API key with reveal toggle,
  base URL (e621 / e926 / custom), Save + Test connection
- Credentials are fetched from the backend and held in memory only,
  cleared on logout
2026-09-17 08:49:00 -05:00
JakeBreath a09ab8a160 Shell shortcuts: /, D, [ ], Ctrl+K palette + neighbors endpoint
Backend:
- GET /api/files/{md5}/neighbors/ returns previous/next items in the
  current ordering (name, size, created_at) for keyboard navigation

Frontend:
- / focuses the library search input
- D downloads the file on the detail page
- [ and ] navigate to the previous/next item; hint shown on the page
- Ctrl/Cmd+K opens a command palette (navigation, toggle filters,
  focus search, log in/out); Escape closes it
- Sort order now persists alongside the other library filters so
  prev/next stays consistent
2026-09-17 08:33:22 -05:00
JakeBreath cc625d1e10 Fix shell details: distro name, storage path only in footer
- OS name comes from /etc/os-release (e.g. 'CachyOS Linux'), mirroring
  the original app's os_utils; macOS/Windows get proper names too
- Status pill shows the name as-is instead of uppercasing it
- Removed the watched-folder path next to the logo; it now appears only
  in the footer strip (spec updated to match)
2026-09-17 08:26:14 -05:00
JakeBreath 3aa42f3703 Shell polish: storage line, status pill, footer strip, sidebar
Backend:
- apps.core with GET /api/status/ (env, git hash, OS, watched folder,
  worker counts) and a TimingMiddleware adding X-Server-Time-Ms
- status endpoint reports its own server-side assembly time

Frontend:
- top bar shows the storage line (watched folder) and a status pill
  with ENV, git hash, host OS, server time (e621 time once it exists)
- fixed 32px footer strip: storage path, active workers, build version
- collapsible filter sidebar: closed by default, Ctrl/Cmd+B toggle,
  overlay drawer with backdrop blur under 1024px
- rating filters, per-page and sidebar state persist in localStorage
2026-09-17 08:19:27 -05:00
JakeBreath 555c25d77b M0: scaffold SPA + API monorepo
Backend (Django 6.1 + DRF):
- Token auth with a custom User model (register/login/logout/me)
- Library models (MediaItem, MediaLocation) and REST endpoints
- File list/detail with search, rating filter, sorting, pagination
- Multipart upload with optional rating/tags/notes
- Range-aware media serving (video seeking) and ffmpeg thumbnails
- scan_files management command for the watched folder

Frontend (React 19 + Vite + TypeScript):
- Catppuccin Mocha design tokens from the design docs
- App shell, token persistence, protected routes
- Library grid with filters, file detail with custom data editor
- Upload page with per-file progress via XHR
- Dev proxy to the Django API
2026-09-17 07:56:47 -05:00