Your intelligent media discovery companion powered by AI.
Watch Wise is a modern web application built with Nuxt 4 that helps you discover your next favorite movie or TV show. It combines data from TMDB and TheTVDB with AI-powered recommendations from OpenAI to provide personalized suggestions.
-
Browse Library: Explore a curated collection of 100+ movies and TV shows
- Separate tabs for Movies and TV Shows
- Search functionality across all titles
- Pagination for easy browsing
- Rating and genre information
-
AI-Powered Recommendations: Get personalized suggestions
- Natural language chat interface
- AI-ranked recommendations with rationale
- Mixed results from TMDB and TheTVDB
- Direct links to external provider pages
-
Graceful Degradation: Works without API keys
- Falls back to seed data when external providers unavailable
- Deterministic ranking when OpenAI is not configured
- Clear error messages and status indicators
- Framework: Nuxt 4
- UI Library: Nuxt UI (built on Headless UI and Tailwind CSS)
- Styling: Tailwind CSS 4
- External Providers:
- TMDB (The Movie Database) for movie metadata
- TheTVDB for TV show metadata
- OpenAI for AI-powered ranking and rationale
- Node.js 18+ or Bun
- (Optional) API keys for external providers
-
Clone the repository
-
Install dependencies:
npm install # or bun install -
Copy
.env.exampleto.envand configure your API keys (optional):cp .env.example .env
-
Start the development server:
npm run dev # or bun run dev
The app works without API keys using seed data. To enable full functionality:
- TMDB: Get your bearer token from themoviedb.org/settings/api
- TheTVDB: Get your API key from thetvdb.com/dashboard/account/apikeys
- OpenAI: Get your API key from platform.openai.com/api-keys
Add these to your .env file:
NUXT_TMDB_BEARER_TOKEN=your_token_here
NUXT_THETVDB_API_KEY=your_key_here
NUXT_THETVDB_PIN=your_pin_here # Optional
NUXT_OPENAI_API_KEY=your_key_herewatch-wise/
├── app/
│ ├── pages/ # Route pages
│ │ ├── index.vue # Home page
│ │ ├── library.vue # Library browse page
│ │ └── recommendations.vue # Recommendations chat page
│ └── types/
│ └── library.ts # Shared TypeScript types
├── server/
│ ├── api/ # API endpoints
│ │ ├── library.get.ts
│ │ ├── library/status.get.ts
│ │ └── recommendations/chat.post.ts
│ ├── data/
│ │ └── library.mock.json # Seed data
│ ├── plugins/
│ │ └── library-sync.ts # Startup sync plugin
│ └── utils/
│ ├── api-error.ts # Error handling utilities
│ ├── env.ts # Runtime config helpers
│ ├── library-store.ts # In-memory library store
│ ├── recommendation-pipeline.ts
│ └── providers/ # External provider clients
│ ├── tmdb.ts
│ ├── tvdb.ts
│ └── openai.ts
└── nuxt.config.ts
GET /api/library- Get paginated library items- Query params:
type,search,page,pageSize
- Query params:
GET /api/library/status- Get library sync status
POST /api/recommendations/chat- Get AI-ranked recommendations- Body:
{ query: string, limit?: number }
- Body:
npm run typechecknpm run buildnpm run preview- Server-side Provider Clients: All external API calls happen on the server
- In-memory Snapshot Store: Library data cached in memory with startup refresh
- Type-safe API Responses: Standardized error/success envelopes
- Graceful Error Handling: Fallbacks at every layer (providers, AI, data)
- Auto-refresh Tokens: TheTVDB token automatically refreshed when expired
MIT