Commit Graph
56 Commits
Author SHA1 Message Date
RXWatcher ace830d9e2 Merge remote-tracking branch 'origin/main' into feat/audiobooks
# Conflicts:
#	go.sum
2026-05-27 16:27:25 +02:00
RXWatcherandClaude Opus 4.7 01fbf54e7d feat(abs): dedicated compat listener on :13378
Mounts the Audiobookshelf-compatible API on its own http.Server so
discovery probes (/ping, /healthcheck, /status, /login, /socket.io)
own the URL space at the root without colliding with silo's SPA
fallback. Mirrors the Jellyfin compat pattern at :8096.

Also adds the ABSRecommender adapter, wired into ABSHandlerDeps via
recommendations.NewRepo + catalog.DetailService. The recommender file
was previously untracked; service.go has already been referencing
ABSRecommender, so HEAD did not build without it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 16:16:26 +02:00
Quick a7f62020fd fix(auth): gate media file paths on metadata curation permission
- Allow curators (not just admins) to view media file paths and locations
- Apply library access filter to file-level access checks
2026-05-26 20:04:54 -04:00
Quick 3d791e2e9f test(auth): expand session revocation coverage 2026-05-26 19:41:55 -04:00
Quick c7d69e9ea2 fix(auth): tighten curator job response review fixes 2026-05-26 19:34:16 -04:00
Quick 21e318dc16 fix(auth): address metadata curation review issues 2026-05-26 19:27:56 -04:00
Quick 6c030d6b76 feat(api): route metadata curation by permission 2026-05-26 18:18:19 -04:00
Quick 6004dd2ddd feat(api): authorize item metadata curation 2026-05-26 18:15:05 -04:00
Quick 6f783a4a6e feat(auth): expose user permissions 2026-05-26 18:13:32 -04:00
Quick 28196232c9 feat(subtitles): restore upload management 2026-05-26 17:57:26 -04:00
QuickandGitHub 14fb677ed9 Merge pull request #8 from Silo-Server/t3code/jellyfin-autoscan-scan-compat
feat(jellycompat): support Autoscan via Jellyfin media-update endpoint
2026-05-26 08:33:48 -04:00
RXWatcher 71174db04e Merge remote-tracking branch 'origin/main' into feat/audiobooks
# Conflicts:
#	AGENTS.md
#	Makefile.local.example
#	internal/metadata/tmdb/client.go
#	web/src/components/AppSidebar.tsx
2026-05-25 19:50:59 +02:00
RXWatcherandClaude Opus 4.7 14a05bba9f feat(audiobooks): comprehensive UX, scanner, and collections work
Detail page:
- collapse Chapters section behind header toggle (73-chapter pages no
  longer push content below the fold)
- square cover frames throughout (audiobook covers are Audible-style 1:1,
  not 2:3 book portrait)
- narrator picker dropdown when multiple narrations of the same book exist
- clickable genre badges (route to /audiobooks?genre=X)
- reordered so credits/rails sit above the chapter list
- Play-from-Start button forces remount via playToken counter (was a
  no-op when player was already at position 0)
- regression test for the Play-from-Start fix

Mini bar / Now Listening:
- mini bar respects --app-sidebar-offset so it stops getting covered by
  the desktop sidebar
- Now Listening adds overflow scroll + a labeled "Back to player" button
  so controls are never inaccessible on short viewports

Library page:
- infinite scroll (replaces Previous/Next pagination)
- genre filter chip with X-to-clear

Scanner:
- 8-worker parallel reconcile (env SILO_AUDIOBOOK_SCAN_WORKERS to override)
- file-path-first dedup so cleaned titles don't collapse separate
  narrations
- title cleanup at write time (strips "Read by X" / "(unabridged)"
  suffixes; original tag preserved in original_title)
- audiobook_series upsert from tag-derived series_name/series_position
- secondary dedup check (author + narrator + year + duration ±0.5% +
  title-prefix) so two folders of the same book attach to one row

Backend detail handler:
- new fetchAlsoByAuthor, fetchInSeries (with series row > 1 entry guard),
  fetchSimilar (embedding-first with shared-genre fallback),
  fetchOtherNarrations (regex-strips narrator suffix to group siblings)
- audiobookDetailResponse gained also_by_author, in_series,
  similar_audiobooks, other_narrations fields
- list endpoint accepts a genre query param

Embeddings:
- BuildEmbeddingText branches on item.Type == "audiobook" to use
  author/narrator credits instead of cast/director/writer
- mediaTypeLabel helper centralizes movie / "TV series" / audiobook
- ListEmbeddingTextCandidates SQL mirrors the Go branching exactly
- ItemsNeedingEmbedding and TotalMediaItemCount loosen status='matched'
  gate to also include audiobooks (which don't go through TMDB match)
- FindSimilar gains a mediaType filter so cross-type results never appear
- callers in similar.go and personal.go pass the source item's type

Collections:
- MediaAudiobook MediaKind + audiobook(s) case in templateEligibleForLibrary
  (stops offering broken movie/TV templates to audiobook libraries)
- useAddItemToCollection hook (user + admin/library endpoints)
- AddToCollectionDialog wired into audiobook detail and movie/series
  ActionBar overflow menu
- ManualCollectionItemsEditor gained a search-and-add panel with
  debounced live results
- QueryDefinition.media_scope, QuerySortRelevanceScope, ALL_MEDIA_SCOPES
  extended to include "audiobook"
- CatalogFilterBar gained an Audiobooks media scope option
- parseCatalogMediaScope (backend) accepts "audiobook"

Migrations:
- 145_audiobook_series: per-book series_name/series_index with a
  best-effort title-pattern backfill for the existing corpus
- 146_audiobook_title_cleanup: strips narrator suffix / (unabridged)
  noise from existing titles, preserving raw in original_title

Scripts:
- scripts/dedup_audiobooks.py: one-shot merge for "Title" vs
  "Title: Subtitle" duplicates, file-path-stable, dry-run by default

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 19:47:54 +02:00
Silo Server Migration a05a0d26a2 refactor(scantrigger): drop redundant Target.LibraryID field
- Read library ID from Target.Folder.ID everywhere
- Guard scan queue enqueue against nil Folder
- Simplify admin API key auth error plumbing
2026-05-25 12:11:56 -04:00
Silo Server Migration 98ea57ead8 chore: add planning docs and requests updates
- Add plans for date-named episodes and Jellyfin autoscan compat
- Update requests handlers, service, and UI hooks
- Remove Makefile.local.example
2026-05-25 12:07:50 -04:00
Silo Server Migration 97e9e9c106 refactor(api): share scan target resolution 2026-05-25 11:18:02 -04:00
QuickandGitHub 6080cbad72 Merge pull request #7 from Silo-Server/t3code/discover-studios-networks-genres-clean
feat(requests): add media request system
2026-05-25 10:56:57 -04:00
Silo Server MigrationandClaude Opus 4.7 8a86e0cf08 refactor: tmdb and requests polish
- GetExternalIDs now uses the dedicated /movie/{id}/external_ids and
  /tv/{id}/external_ids endpoints instead of fetching the full detail
  with append_to_response=external_ids. The dedicated payload is
  one or two orders of magnitude smaller for the same fields.
- Document PosterPath/BackdropPath on MediaResult as raw TMDB path
  fragments that callers must prefix with the image base URL.
- normalizeCast switches from inline insertion sort to sort.SliceStable.
  The output is identical; the new form is one line and O(n log n).
- normalizeIntegration no longer reuses integration.Tags' backing
  array via Tags[:0]; the slice is callable code, so reusing the
  array would silently corrupt the caller's slice if it kept a
  reference. Allocate a fresh slice instead.
- HandleGet now requires a profile, matching the rest of the
  /requests user-group handlers. Router middleware enforces this
  already, but the inline check is defense-in-depth for any future
  remount.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 00:27:39 -04:00
Silo Server MigrationandClaude Opus 4.7 34f92fdc1d refactor(requests): consolidate shared Arr client helpers
The radarr and sonarr clients carried byte-identical copies of
rootFolderResource, qualityProfileResource, tagResource (and the
corresponding list helpers) plus acceptedWithoutResponse and
statusFromQueueEvaluation. Move the shared wire types and helpers
into the arrclient package and update the callers to use the
exported helpers. No behavior change.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 00:21:50 -04:00
Silo Server MigrationandClaude Opus 4.7 38868b2128 feat(requests): add cancel endpoint and tighten state guards
Owners can now POST /requests/{id}/cancel to withdraw a pending
request; admins can cancel any active request that has not entered
the fulfillment pipeline. The route is mounted on both the user
group (with profile required) and the admin group. The cancelled
outcome was already reserved in the migration's CHECK constraint
but was unreachable from any handler.

Decline now also rejects approved requests — between Approve setting
StatusApproved and the reconciler picking the request up, an admin
could declare the request declined while submission was about to
fire. The reconciler's outcome filter would skip the request, but
the narrow window meant external state could diverge from Silo's
view. Refuse decline once a request is approved; callers should
wait for completion or use the failed/retry path.

Reconcile now emits a slog.WarnContext at the per-request failure
site with request id, media type, tmdb id, status, and integration
kind. Aggregated counters in ReconcileResult are unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 00:16:41 -04:00
Silo Server Migration 1339b9b5c9 feat(requests): match catalog presence by external ids 2026-05-24 22:45:50 -04:00
Silo Server Migration 98bebd4e5e fix(requests): harden integration submission and queue handling
- Batch integration upserts in a single transaction
- Treat radarr/sonarr lookup results as arrays and require exact matches
- Prefer queue failures over downloading state when evaluating arr queues
- Allow retrying queued/downloading requests and block declines once fulfillment started
- Fall back to pending when auto-approval integration check fails
- Rename requests query hooks file and fix discover card request affordance
2026-05-24 21:40:34 -04:00
Silo Server MigrationandCursor 509a6c84ba feat(requests): add discover studios, networks, and genres
Wire curated TMDB-backed studios/networks/genres discovery into the requests service and UI, replacing on-demand logo fetches with fixed duotone logos and adding browse routes plus tests.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-24 19:53:21 -04:00
Silo Server Migration 4321cb797c feat(api): wire discover studios/networks/genres routes 2026-05-24 18:42:02 -04:00
Silo Server Migration 8789249f44 feat(api): add discover brand and browse handlers 2026-05-24 18:41:31 -04:00
RXWatcherandClaude Opus 4.7 ac31c9d17e chore(audiobooks): snapshot in-progress work as pre-redesign baseline
Bundles 21 in-progress files spanning scanner, image cache, ABS API
handlers, podcast/audiobook scan, cover enrichment, metadata sync
task, and an interim pass at the audiobook detail page (DetailHero
adoption + fixed-bottom player). Committed as a single baseline so
the upcoming UI redesign (per the 2026-05-24 plan) starts from a
clean working tree. Not split into logical commits because this
captures pre-existing local work, not a curated change.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 23:24:11 +02:00
Silo Server Migration 5b8aa9f34c feat(requests): add media detail page with TMDB metadata
- Add GetMediaDetail TMDB client returning normalized detail with cast, crew, recommendations, and certifications
- Add /api/requests/detail/{media_type}/{tmdb_id} endpoint overlaying availability and request state
- Add RequestDetail page and link poster cards to it
- Treat empty/truncated Radarr/Sonarr POST responses as accepted; drop pre-submit existence lookups
2026-05-24 17:03:29 -04:00
Silo Server Migration 246c9da6ab feat(requests): add media request system with Radarr/Sonarr fulfillment
- Add request domain, repository, service, and reconcile task
- Add Radarr/Sonarr fulfillment adapters and TMDB discovery
- Expose user and admin request APIs with quota and approval rules
- Add web UI for browsing, requesting, and admin queue management
- Migration 139 introduces media_requests and related tables
2026-05-24 13:58:12 -04:00
RXWatcherandClaude Opus 4.7 64e30997cb feat(audiobooks): wire ABS routes into main router
Stage 7 of the ABS-compat port (final). Implements MediaStore, ConfigProvider,
and event/recommender stub adapters, constructs the abs.Handler in
cmd/silo/main.go, and mounts it under /abs and /abs/api on silo's main
router. ABS-compatible Audiobookshelf clients can now hit silo
directly for login, library + items browse, file streaming, progress,
and Socket.io.

End-to-end smoke verified: /login returns 401, /abs/api/login returns
401, /abs/api/me returns 401, /abs/api/libraries returns 401,
/abs/socket.io/ returns 200 on polling handshake.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 15:58:02 +02:00
RXWatcherandClaude Opus 4.7 75cff9f441 feat(audiobooks): progress endpoint at POST /api/v1/audiobooks/{id}/progress
UPSERTs user_watch_progress for the caller's (user_id, profile_id,
content_id). Body carries position_seconds; clients are expected to
post every 5-10s during playback plus on pause/seek (matching silo's
existing video progress cadence).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 14:40:50 +02:00
RXWatcherandClaude Opus 4.7 1ce29ac60d feat(audiobooks): detail endpoint at GET /api/v1/audiobooks/{id}
Returns the media_items row, its media_files (with chapters JSONB),
author/narrator extracted from item_people (kinds 7/8), and the
caller's per-profile listening progress from user_watch_progress.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 14:38:17 +02:00
RXWatcherandClaude Opus 4.7 cc12ab5d5d feat(audiobooks): list endpoint at GET /api/v1/audiobooks
Paginated list of media_items with type='audiobook' scoped to the
caller's accessible libraries via the existing access filter.
Mirrors silo's existing list-style handlers for movies and series.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 14:33:21 +02:00
RXWatcherandClaude Opus 4.7 39e98a3e90 fix(api): allow HEAD on /api/v1/direct-download
Firefox (and some download managers) issue a HEAD request before
starting a download. The route only registered GET, so HEAD returned
405 Method Not Allowed and the browser aborted the download.

Mirrors the pattern already used by /stream/{session_id}, which
registers both GET and HEAD on the same handler. ServeDirect is built
on http.ServeContent / ServeFile, which natively handle HEAD by
writing headers without a body, so no handler changes are needed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 08:57:42 +02:00
RXWatcherandClaude Opus 4.7 8d01dad757 fix(api): allow HEAD on /api/v1/direct-download
Firefox (and some download managers) issue a HEAD request before
starting a download. The route only registered GET, so HEAD returned
405 Method Not Allowed and the browser aborted the download.

Mirrors the pattern already used by /stream/{session_id}, which
registers both GET and HEAD on the same handler. ServeDirect is built
on http.ServeContent / ServeFile, which natively handle HEAD by
writing headers without a body, so no handler changes are needed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 08:57:42 +02:00
QuickandGitHub f8dcdd0554 Merge pull request #3 from Silo-Server/t3code/ef35ed7f
Rename webhook sync actors to profile mappings
2026-05-24 00:55:41 -04:00
QuickandGitHub cdf5fe3a50 Merge pull request #3 from Silo-Server/t3code/ef35ed7f
Rename webhook sync actors to profile mappings
2026-05-24 00:55:41 -04:00
Silo Server Migration d41ffd4d5e Add live introdb key reload and recap playback markers
- reload introdb API key on setting updates
- support recap/preview markers in playback and next-episode flow
- add profile defaults for recap and preview auto-play settings
2026-05-24 00:14:17 -04:00
Silo Server Migration b1f2d164ac Add live introdb key reload and recap playback markers
- reload introdb API key on setting updates
- support recap/preview markers in playback and next-episode flow
- add profile defaults for recap and preview auto-play settings
2026-05-24 00:14:17 -04:00
Silo Server Migration 5f5e404d93 Rename webhook sync actors to profile mappings
- Rename actor-oriented API, storage, and webhook fields to user/profile terminology
- Switch dev compose helpers to use docker-compose.yml
- Update frontend types and webhook sync settings for the new endpoints
2026-05-24 00:04:25 -04:00
Silo Server Migration f1e82f1eec Rename webhook sync actors to profile mappings
- Rename actor-oriented API, storage, and webhook fields to user/profile terminology
- Switch dev compose helpers to use docker-compose.yml
- Update frontend types and webhook sync settings for the new endpoints
2026-05-24 00:04:25 -04:00
Silo Server Migration 04a7e8c82d Add online marker support for recap and preview segments
- Wire introdb marker fetching into playback and Jellyfin compat
- Persist and expose recap/preview markers alongside intro and credits
- Add new playback/profile settings for recap and preview behavior
2026-05-23 23:48:25 -04:00
Silo Server Migration ea92f7a311 Add online marker support for recap and preview segments
- Wire introdb marker fetching into playback and Jellyfin compat
- Persist and expose recap/preview markers alongside intro and credits
- Add new playback/profile settings for recap and preview behavior
2026-05-23 23:48:25 -04:00
Silo Server Migration 4c2fcdfff0 Handle bundled collection poster failures gracefully
- Log poster store/update failures instead of aborting collection sync
- Preallocate matched collection replacements using the active limit
2026-05-23 21:32:22 -04:00
Silo Server Migration 08fff4db68 Handle bundled collection poster failures gracefully
- Log poster store/update failures instead of aborting collection sync
- Preallocate matched collection replacements using the active limit
2026-05-23 21:32:22 -04:00
Silo Server Migration 0d1f40f8c4 Queue template bundle applies in background
- Add admin job support for collection defaults applies
- Keep preview synchronous while real applies run via the job queue
- Show collection apply job status in the admin UI
2026-05-23 21:19:33 -04:00
Silo Server Migration bad0a3d74a Queue template bundle applies in background
- Add admin job support for collection defaults applies
- Keep preview synchronous while real applies run via the job queue
- Show collection apply job status in the admin UI
2026-05-23 21:19:33 -04:00
Silo Server Migration 9c3848d205 Port collection templates to bundled poster storage
- Store bundled template posters in public S3 when available
- Presign imported user collection posters in API responses
- Thread frontend assets into router and collection handlers
2026-05-23 20:26:05 -04:00
Silo Server Migration 01b9709e4f Port collection templates to bundled poster storage
- Store bundled template posters in public S3 when available
- Presign imported user collection posters in API responses
- Thread frontend assets into router and collection handlers
2026-05-23 20:26:05 -04:00
Silo Server Migration 73849214ad fix(collections): address template sync review comments 2026-05-23 17:43:35 -04:00
Silo Server Migration 70b8f6ca2c fix(collections): address template sync review comments 2026-05-23 17:43:35 -04:00