Commit Graph
151 Commits
Author SHA1 Message Date
jakeandClaude Opus 4.6 17c6b23e23 Fix nav bar flash of sign-in/register buttons on load
The pages layout already guards auth server-side, so the unauth
branch in NavBar was dead code causing a flash while useSession loaded.
Render nav links and controls unconditionally instead.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 11:55:27 -05:00
jakeandClaude Opus 4.6 6f415ad0b2 Fix episodes not showing as watched when marking title completed
Optimistically update episodeWatches client state when setting status
to "completed" on a TV title, so episodes render as watched immediately
without requiring a page refresh.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 11:51:46 -05:00
jakeandClaude Opus 4.6 ec256b7a96 Replace keyboard system with TanStack Hotkeys and jotai atoms
Remove react-hotkeys-hook, KeyboardProvider context, useRegisterShortcut
wrapper, and KeyboardHelpDialog component. Components now call TanStack
useHotkey/useHotkeySequence directly. Shared state uses jotai atoms in
lib/atoms/, shortcut metadata lives as a static const in lib/constants/.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 11:48:14 -05:00
jake d5e985efd9 Add auth guards to search and discover API routes 2026-03-03 11:13:14 -05:00
jakeandClaude Opus 4.6 f6ee32ca1e Add confirmation toasts to settings actions and fix webhook card spacing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 11:10:28 -05:00
jakeandClaude Opus 4.6 8487c3d7b1 Convert settings page to server component with server actions
Replace client-side data fetching with server-side queries and server
actions, eliminating 3 API route files. Extract page into granular
client components (account, integrations, server, webhook card) with
optimistic updates. Rename sections: Media Servers → Integrations,
Administration → Server. Add admin badge to account section.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 09:32:18 -05:00
jakeandClaude Opus 4.6 83e2bc5143 Make media server cards collapsible with matching input/button heights
Wrap Plex and Jellyfin webhook cards in collapsible sections with chevron
indicators. Fix input/button height mismatch by using default button sizes
(h-7) instead of lg (h-8). Add Plex Pass requirement info box and move
the enable/disable switch into the collapsible body.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 15:55:00 -05:00
jakeandClaude Opus 4.6 f16ccc2f3f Replace title mutation API routes with server actions
Move all title page mutations (status, rating, movie watch, episode
watch/unwatch, season watch/unwatch) from API route handlers to server
actions called directly from TitleInteractionProvider. Same optimistic
update pattern, no behavioral change — just eliminates the fetch()
round-trip through 5 API routes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 15:47:04 -05:00
jakeandClaude Opus 4.6 c1867a4f23 Convert dashboard and title pages to server components with granular Suspense
Replace fully client-side dashboard and title detail pages with server
component orchestrators that fetch data directly via service functions,
eliminating extra network round-trips through API routes. Each section
streams independently through its own Suspense boundary.

- Extract getUserStats(), getTitleWithChildren(), getRecommendationsForTitle()
  into service layer; update getNewAvailableFeed() to include tmdbId/voteAverage
- Split dashboard into server sections (stats, continue watching, library,
  recommendations) with client children for animations
- Split title page into server hero + client interaction provider with shared
  context for optimistic mutations across actions and seasons
- Add generateMetadata with OG tags, server-side TMDB ID resolution via
  redirect(), loading.tsx and not-found.tsx for both pages
- Add per-section skeleton components, fix ContinueWatchingSkeleton dimensions
- Remove 6 unused API routes (feed/*, titles/[id] GET, titles/[id]/recommendations)
- Remove components/stats-summary.tsx, add lib/types/title.ts for shared types

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 15:42:42 -05:00
jakeandClaude Opus 4.6 081f53beac Add instant navigation from search results via TMDB IDs in URL
Navigate instantly to /titles/tmdb-{id}-{type} and show a skeleton
while the new /api/titles/resolve endpoint handles the full import
(TMDB fetch, availability, recommendations, colors). Existing titles
resolve in ~5ms; the URL is replaced with the UUID once resolved.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 15:13:51 -05:00
jakeandClaude Opus 4.6 18385386d5 Add SQLite connectivity check to healthcheck endpoint
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 14:59:52 -05:00
jakeandClaude Opus 4.6 3455ff9c51 Replace custom CSS tooltips with shadcn Tooltip component
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 14:50:27 -05:00
jakeandClaude Opus 4.6 e89397386c Add TMDB logo link to title page hero metadata
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 14:44:09 -05:00
jake 076108d82a Rename middleware.ts to proxy.ts and export as proxy function 2026-03-02 14:39:56 -05:00
jake f94ceaf233 Move auth protection to middleware and server layout
Replace client-side session checks (useSession + router.replace) with
a two-layer server-side approach: Next.js middleware performs a fast
cookie presence check for all protected routes, and the (pages) layout
does a full server-side session validation before rendering.

Move login/register into a dedicated (auth) route group with its own
minimal layout so they sit outside the authenticated shell. Lift the
Toaster to the root layout so it remains available across all route
groups.
2026-03-02 14:38:54 -05:00
jake c47fe97733 Shift theme base from cool indigo to warm charcoal
Replace the cool indigo hue (270) across all CSS custom properties with
a warm charcoal base (hue 55), giving the dark cinema palette a subtler
amber-tinted warmth. Adjust lightness and chroma values on borders,
inputs, and foreground tokens for improved contrast against the new
base.
2026-03-02 14:27:32 -05:00
jakeandClaude Opus 4.6 936c2e3c8a Apply full-bleed backdrop and fix mobile layout on title pages
Remove breadcrumb navigation, use full-viewport backdrop technique
matching explore page, and fix mobile hero layout: poster and title
info now sit side-by-side at all sizes with a smaller poster and
scaled-down typography on mobile.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 14:19:28 -05:00
jakeandClaude Opus 4.6 978ebfbf3a Fix hero backdrop to span full viewport width on wide screens
Use full-bleed margin technique to break out of max-w-6xl container,
add explicit w-full to prevent aspect-ratio from shrinking the image
container when max-height kicks in, and add overflow-x-hidden to the
page wrapper to prevent scrollbar from 100vw units.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 14:06:48 -05:00
jakeandClaude Opus 4.6 5a2d3fa473 Await recommendations fetch during title import
Recommendations were fetched fire-and-forget, causing a race condition
where the title detail page would load before recommendations were
populated in the database, making the section appear intermittently.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 13:55:57 -05:00
jakeandClaude Opus 4.6 8c31784094 Replace Sofa text branding with sofa icon logo
Swap the "Sofa" wordmark for an SVG sofa icon across the nav bar,
auth forms, and landing page. Add SVG favicon replacing the old .ico.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 13:53:37 -05:00
jake 2f0fe02d26 Fix color extraction and image cache setup in development
Move `ensureImageDirs` outside the production-only block so the local
image cache directories are created in dev mode too. Update
`extractAndStoreColors` to download the poster if it isn't cached yet
instead of falling back to a direct TMDB CDN URL, keeping color
extraction consistent with the server-side image routing approach. Add
`/data` to `.gitignore` to avoid committing the local cache directory.
2026-03-02 13:49:57 -05:00
jakeandClaude Opus 4.6 8eb1007612 Fix stale TMDB poster paths on landing page
Replace 4 broken poster paths (The Dark Knight, Interstellar, Breaking
Bad, The Office) and correct the Forrest Gump path which was incorrectly
using Interstellar's poster.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 13:16:27 -05:00
jakeandClaude Opus 4.6 ee723e41d6 Add TMDB image caching pipeline and resolve image URLs server-side
Introduce a local disk cache for TMDB images served through a proxy API
route (/api/images/[...path]), eliminating direct client-side CDN
dependencies. Images are cached by category (posters, backdrops, stills,
logos) and served with immutable cache headers.

Move all tmdbImageUrl() calls from client components to API routes and
server components so clients receive ready-to-use URLs. This removes the
need to expose TMDB_IMAGE_BASE_URL and IMAGE_CACHE_ENABLED via
next.config.ts env block. The landing page is split into a server
wrapper (app/page.tsx) and client component (components/landing-page.tsx).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 13:10:17 -05:00
jakeandClaude Opus 4.6 cb0f366d44 Add dynamic color theming from poster art using node-vibrant
Extract dominant colors from movie/TV poster images server-side and use
them to create per-title atmospheric effects on detail pages — tinted
backdrop gradients, ambient glow orbs, and colored poster shadows.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 12:29:13 -05:00
jakeandClaude Opus 4.6 67356e04c6 Add Plex and Jellyfin webhook integration for automatic watch tracking
When a user finishes watching on their media server, a webhook fires and
Sofa logs it as watched, triggering all existing auto-transitions. Each
user configures their connection in settings and gets a unique webhook URL.

- Add webhookConnections and webhookEventLog schema tables
- Add TMDB findByExternalId for resolving IMDB/TVDB IDs
- Add source parameter to tracking functions (plex/jellyfin)
- Add webhook processing service with payload parsers, title resolution,
  and deduplication
- Add public webhook receiver route (token-based auth)
- Add authenticated settings API routes for managing connections
- Add Media Servers section to settings UI with Plex/Jellyfin cards

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 16:24:39 -05:00
jakeandClaude Opus 4.6 e098180dda Replace search page with explore page for rich discovery experience
The command palette (⌘K) already handles direct title search. Replace the
redundant /search page with a new /explore page featuring trending titles,
popular movies/TV, and genre browsing powered by TMDB discovery endpoints.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 15:11:53 -05:00
jakeandClaude Opus 4.6 cddef34909 Move healthcheck into Dockerfile and simplify docker-compose.yml
Uses BusyBox wget (included in Alpine) instead of Node.js fetch for the
health check. docker-compose.yml now references the published GHCR image
instead of building locally.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 14:54:05 -05:00
jakeandClaude Opus 4.6 2995d89154 Rename TMDB_API_KEY to TMDB_API_READ_ACCESS_TOKEN and add optional base URL overrides
Renames the env var for clarity since it holds a read access token, not an API
key. Adds optional TMDB_API_BASE_URL and TMDB_IMAGE_BASE_URL env vars for
advanced users. Centralizes image URL construction into a shared tmdbImageUrl()
helper, replacing hardcoded URLs across all components.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 13:55:58 -05:00
jakeandClaude Opus 4.6 db3a6cc3d4 Add auto-close registration and admin settings page
First user to register automatically becomes admin and registration
closes. Admins can re-open registration from a new settings page.
Uses Better Auth admin plugin for role management and a new appSettings
table for the registration flag. Mobile tab bar now links to settings
instead of inline logout.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 13:51:20 -05:00
jake c0ba717a93 Refactor setup page text for clarity by simplifying API token description 2026-03-01 13:37:30 -05:00
jake ea0f00945d Add .gitkeep file to drizzle directory for version control 2026-03-01 13:31:28 -05:00
jakeandClaude Opus 4.6 8fc4c110b6 Add setup page and graceful handling for missing TMDB API key
Without TMDB_API_KEY the app silently fails on search and import.
This adds a /setup page that guides admins through obtaining and
configuring the key, redirects unconfigured visitors from the
landing page, and returns clear error messages from the search API.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 13:30:31 -05:00
jakeandClaude Opus 4.6 fa57bf9476 Rename app from "Couch Potato" to "Sofa"
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 13:23:54 -05:00
jakeandClaude Opus 4.6 46e75dafc2 Add CI/CD workflow for multi-arch Docker builds to GHCR and Docker Hub
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 13:20:50 -05:00
jakeandClaude Opus 4.6 96213c3086 Add Docker packaging and migrate from better-sqlite3 to libsql
Docker self-hosting support:
- Dockerfile (multi-stage Alpine build with tini init)
- docker-compose.yml with named volume for SQLite persistence
- /api/health endpoint for container health checks
- Auto-migration on startup via drizzle-orm/libsql/migrator
- Graceful shutdown (SIGTERM stops scheduler, closes DB)
- Next.js standalone output mode for minimal image size

Database driver migration (better-sqlite3 → @libsql/client):
- Eliminates native C++ compilation, enabling Alpine Docker images
- All DB queries converted from sync to async across services and routes
- DATABASE_URL now uses libsql file: prefix format
- drizzle.config.ts dialect changed to turso for libsql support
- Initial migration files generated in drizzle/

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 13:14:57 -05:00
jake 8f99a20a9c Add MIT License file to the project 2026-03-01 11:52:03 -05:00
jake 3851b71f94 Remove unused SVG files from the public directory to streamline assets and reduce clutter. The following files were deleted: file.svg, globe.svg, next.svg, vercel.svg, and window.svg. 2026-03-01 11:50:59 -05:00
jakeandClaude Opus 4.6 0e8ea15cd0 Mobile viewport fixes: responsive card width, nav cleanup, season percentages
- Continue Watching card uses viewport-relative width on mobile (calc(100vw-3rem))
  with edge-to-edge scroll container using negative margin trick
- Nav bar hides user name on mobile (bottom tab bar shows it instead)
- Season rows show percentage text on mobile where progress bar is hidden
- Season 5 correctly shows "94%" instead of requiring the hidden progress bar

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 11:50:02 -05:00
jake b96c7ac540 Add browser automation section to CLAUDE.md
- Introduced a new section detailing the use of `agent-browser` for web automation.
- Included core workflow commands for navigating and interacting with web pages.
- Provided instructions for capturing interactive elements and re-snapshotting after changes.
2026-03-01 11:42:17 -05:00
jakeandClaude Opus 4.6 8f80620aaf Add floating poster collage to landing page for visual context
- 12 well-known movie/TV posters arranged in tilted columns behind hero
- Low opacity (12%) with radial gradient fade keeping center text clear
- Spring entrance animations with staggered delays
- Posters hidden on mobile (sm:block) for clean experience on small screens
- Added next/image for optimized poster loading

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 11:39:21 -05:00
jakeandClaude Opus 4.6 989b5e4cd0 Improve title detail: episode stills, descriptions, provider tooltips, stronger gradient
- Episode rows now show still images (thumbnail, hidden on mobile)
- Episode descriptions shown as 2-line clamp below title on desktop
- Watched episodes dimmed with opacity for clear visual differentiation
- Provider logos get CSS hover tooltips showing the service name
- Backdrop gradient strengthened with extra overlay layer for text
  readability on bright/colorful backdrop images
- Added stillPath to Episode interface

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 11:36:15 -05:00
jakeandClaude Opus 4.6 30d074e2ca Add mobile bottom tab bar for small screen navigation
- New MobileTabBar component with Home, Search, and Account tabs
- Animated indicator follows active tab (spring layoutId transition)
- Shown only below sm breakpoint where desktop nav links are hidden
- Account tab provides quick sign-out access
- Safe area padding for devices with home indicators
- Added bottom padding to layout to prevent content overlap

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 11:33:52 -05:00
jakeandClaude Opus 4.6 f7d5179d0f Enhance dashboard: richer continue watching cards, color-coded stats, styled poster fallback
- Continue Watching cards now show episode still images in 16:9 aspect
  with overlaid episode info, play button, and progress bar
- Stats section uses per-stat color coding (primary/watching/watchlist/completed)
  with icon background pills and tabular-nums alignment
- No-poster fallback replaced with textured gradient + title text overlay
- Updated ContinueWatchingItem interface to include backdropPath, stillPath, overview

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 11:32:17 -05:00
jakeandClaude Opus 4.6 0aac1d0d37 Add unwatch support for episodes/seasons, fix nested button hydration error
Toggle episode watched state, bulk unwatch seasons via new DELETE endpoints,
and replace outer <button> with <div role="button"> in season accordion to
avoid invalid nested button HTML that caused hydration errors.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 11:15:44 -05:00
jakeandClaude Opus 4.6 bebc4dc9fa Fix intermittent missing episodes for TV shows
TV episodes were missing when: (1) a title existed as a recommendation
"shell" with no episode data, (2) a prior refreshTvChildren() call
failed partway through, or (3) the title detail page was loaded before
episodes finished importing. importTitle() now re-fetches episodes for
existing TV titles with zero seasons, the GET endpoint hydrates shell
titles on access, and refreshTvChildren() handles per-season errors
gracefully instead of aborting entirely.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 11:10:04 -05:00
jake dcb48eaf37 Add /dashboard route, mark-all-watched on complete, keyboard fixes
- Move dashboard page to app/(pages)/dashboard, redirect / to /dashboard
  for authenticated users, update all nav/breadcrumb/auth hrefs
- Mark all episodes watched when a TV show status is set to "completed"
  (markAllEpisodesWatched skips already-watched episodes)
- Refactor KeyboardProvider to store shortcuts in a ref instead of
  state, eliminating unnecessary re-renders; use react-hotkeys-hook for
  Cmd+K so it works reliably in form inputs
- Fix useRegisterShortcut: re-register on every render (stable ref read)
  with a separate cleanup effect, removing brittle key memoization
- Search page: silently navigate to title detail on import instead of
  showing "Added to library" toast
2026-03-01 11:06:26 -05:00
jakeandClaude Opus 4.6 b6aaad243f UX overhaul: motion animations, command palette, warm cinema theme
Add premium "Late Night Screening Room" experience with warm indigo/amber
palette, framer-motion spring animations, Cmd+K command palette with TMDB
search, keyboard shortcuts (G H, G S, ?, W, M, 1-5), sonner toasts with
optimistic updates, skeleton loading states, stats dashboard, search
autocomplete with filter tabs, cinematic backdrop with film grain, season
progress bars, and staggered card reveal animations throughout.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 15:30:35 -05:00
jakeandClaude Opus 4.6 095b64ab42 Simplify auth, remove abstraction layers, add shadcn components
- Delete lib/api/errors.ts and lib/api/auth-guard.ts, inline
  NextResponse.json() error responses directly in route handlers
- Replace non-standard amber CSS variables with primary/primary-foreground
- Regenerate shadcn UI components with biome-ignore comments
- Add CLAUDE.md for repository guidance
- Update dependencies and pnpm lockfile

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 15:00:15 -05:00
jakeandClaude Opus 4.6 b02ff1cdc1 Implement full Couch Potato movie & TV tracking app
Add all 10 milestones: Drizzle ORM + SQLite database with WAL mode,
Better Auth email/password authentication, TMDB API integration for
search and metadata import, TV season/episode caching, user tracking
(watchlist/status/watches/ratings with auto-transitions), discovery
feeds (continue watching, library, recommendations), US streaming
availability via TMDB providers, background job scheduler with
instrumentation hook, and dark cinema-themed frontend with DM Serif
Display + DM Sans typography and amber accent design system.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 14:42:13 -05:00
jake 1b0ca5431a shadcn 2026-02-27 14:15:02 -05:00