Skip to content

tonypius/just-ott

Repository files navigation

JustOTT

Find which OTT platform has your favorite Bollywood & regional movies

A serverless web application that helps users discover which OTT platform (Netflix, Prime Video, Disney+, Hotstar, etc.) streams a specific movie. Focuses on Bollywood and regional Indian cinema (Tamil, Telugu, Malayalam, Kannada).

Features

  • Fast Autocomplete Search: Real-time search with typo tolerance powered by Meilisearch
  • Movie Details: Comprehensive information from Wikipedia including cast, director, plot, and more
  • OTT Platform Availability: Shows which platforms currently stream each movie
  • Daily Updates: Automated scraping pipeline to track new OTT releases
  • Regional Cinema Support: Hindi, Tamil, Telugu, Malayalam, Kannada, and more
  • Responsive Design: Mobile-first UI built with shadcn/ui and Tailwind CSS

Tech Stack

Frontend

  • Next.js 14 - React framework with App Router
  • React 18 - UI library
  • Tailwind CSS - Styling
  • shadcn/ui - Component library
  • Lucide React - Icons

Backend

  • Next.js API Routes - Serverless functions
  • Supabase - PostgreSQL database and authentication
  • Meilisearch - Open-source search engine

Data Sources

  • Wikipedia API - Movie details (free, commercial-friendly)
  • News Scraping - OTT release information from entertainment news
  • z.ai/OpenAI API - LLM-powered content extraction

Project Architecture

┌─────────────────────────────────────────────────────────────┐
│                        User Interface                        │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐      │
│  │   Home Page  │  │ Search Page  │  │ Movie Detail │      │
│  └──────────────┘  └──────────────┘  └──────────────┘      │
└─────────────────────────────────────────────────────────────┘
                            │
                            ▼
┌─────────────────────────────────────────────────────────────┐
│                      API Routes (Next.js)                    │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐      │
│  │  /api/search │  │ /api/movie/* │  │/api/cron/*   │      │
│  └──────────────┘  └──────────────┘  └──────────────┘      │
└─────────────────────────────────────────────────────────────┘
           │                    │                    │
           ▼                    ▼                    ▼
┌─────────────────┐  ┌─────────────────┐  ┌─────────────────┐
│   Meilisearch   │  │    Supabase     │  │  RSS Feeds/LLM  │
│  (Search Index) │  │  (PostgreSQL)   │  │  (Scraper)      │
└─────────────────┘  └─────────────────┘  └─────────────────┘

Data Pipeline

  1. Movie Discovery → Wikipedia API search
  2. Movie Details → Parse Wikipedia infobox data
  3. OTT Information → Scrape news articles → Extract with LLM
  4. Search Indexing → Sync to Meilisearch
  5. Daily Updates → Cron job runs scraping pipeline

Prerequisites

  • Node.js 18.x or higher
  • npm or yarn or pnpm
  • Docker (for local Meilisearch)
  • Supabase account (free tier works)
  • z.ai or OpenAI API key (for scraping)

Installation

1. Clone the Repository

git clone https://github.com/yourusername/justott.git
cd justott

2. Install Dependencies

npm install
# or
yarn install
# or
pnpm install

3. Set Up Environment Variables

Copy the example environment file:

cp .env.example .env

Edit .env and add your API keys:

# Supabase
SUPABASE_URL=your_supabase_project_url
SUPABASE_ANON_KEY=your_supabase_anon_key
SUPABASE_SERVICE_ROLE_KEY=your_supabase_service_role_key

# Meilisearch
MEILISEARCH_HOST=http://localhost:7700
MEILISEARCH_MASTER_KEY=your_master_key_here

# z.ai / OpenAI API
ZAI_API_KEY=your_zai_api_key_here
ZAI_API_URL=https://api.openai.com/v1
ZAI_MODEL=gpt-4o-mini

# Cron Security
CRON_SECRET=generate_a_random_secret_here

# App Config
NEXT_PUBLIC_SITE_URL=http://localhost:3000

4. Generate Cron Secret

Generate a secure random secret for protecting cron endpoints:

# On macOS/Linux
openssl rand -base64 32

# Or use Node.js
node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"

Setting Up Services

Supabase Setup

  1. Create a Supabase Project

    • Go to supabase.com
    • Click "New Project"
    • Set your database password (save it!)
  2. Run Database Migrations

    • Go to SQL Editor in Supabase dashboard
    • Copy contents of supabase/migrations/001_initial_schema.sql
    • Paste and run
    • Copy contents of supabase/migrations/002_add_wikipedia_and_scraper_schema.sql
    • Paste and run
  3. Get API Keys

    • Go to Project Settings → API
    • Copy URL, anon key, and service_role key
    • Add to your .env file

Meilisearch Setup

Option 1: Docker (Recommended for Local Development)

  1. Update docker-compose.yml with your master key:

    environment:
      - MEILI_MASTER_KEY=your_actual_master_key_here
  2. Start Meilisearch:

    docker-compose up -d
  3. Verify it's running:

Option 2: Meilisearch Cloud

  1. Sign up at cloud.meilisearch.com
  2. Create a new project
  3. Get your host URL and API keys
  4. Update .env:
    MEILISEARCH_HOST=https://your-project.meilisearch.com
    MEILISEARCH_SEARCH_ONLY_KEY=your_search_key

z.ai / OpenAI Setup

The scraper uses an LLM to extract OTT information from news articles.

Using z.ai (Recommended)

  1. Sign up at z.ai
  2. Get your API key from the dashboard
  3. Add to .env:
    ZAI_API_KEY=your_zai_api_key
    ZAI_API_URL=https://api.openai.com/v1  # or your z.ai endpoint

Using OpenAI

  1. Sign up at platform.openai.com
  2. Create an API key
  3. Add to .env:
    OPENAI_API_KEY=your_openai_api_key

Running the Application

Development Mode

npm run dev
# or
yarn dev
# or
pnpm dev

Open http://localhost:3000 in your browser.

Production Build

npm run build
npm start
# or
yarn build
yarn start
# or
pnpm build
pnpm start

Populating Initial Data

Option 1: Import Sample Movies

Create a script to add some initial movies from Wikipedia:

# Run the seed script
npm run seed

Option 2: Run the Scraper

Manually trigger the scraping pipeline:

# Option 1: Using Authorization header (recommended - no encoding needed)
curl -X POST http://localhost:3000/api/cron/daily-sync \
  -H "Authorization: Bearer YOUR_CRON_SECRET"

# Option 2: Using query parameter (URL encode the secret if it has special characters)
# Special characters like + need to be encoded as %2B
curl "http://localhost:3000/api/cron/daily-sync?secret=YOUR_URL_ENCODED_SECRET"

This will:

  1. Fetch recent articles from configured news sources
  2. Extract OTT release information using LLM
  3. Match movies to Wikipedia data
  4. Store in database
  5. Update Meilisearch index

Option 3: Manual Movie Addition

You can also add movies manually through the Supabase dashboard or by calling the API directly.

Setting Up Cron Jobs

Vercel Cron Jobs

  1. Deploy your app to Vercel
  2. Add your cron secret to Vercel environment variables
  3. Update vercel.json with your schedule:
    {
      "crons": [{
        "path": "/api/cron/daily-sync",
        "schedule": "0 2 * * *"
      }]
    }

Alternative Cron Services

You can also use:

  • GitHub Actions - Create a workflow file
  • Cron-job.org - Free external cron service
  • Your server's cron - Use curl to trigger the endpoint

Deployment

Vercel (Recommended)

  1. Install Vercel CLI:

    npm i -g vercel
  2. Deploy:

    vercel
  3. Add Environment Variables in Vercel Dashboard:

    • Go to Project Settings → Environment Variables
    • Add all variables from your .env file
  4. Deploy to Production:

    vercel --prod

Other Platforms

The app can be deployed to any platform that supports Next.js:

  • Netlify - Use Next.js plugin
  • Railway - Deploy with Docker
  • Self-hosted - Use Docker Compose

Project Structure

justott/
├── app/                          # Next.js App Router
│   ├── (main)/                   # Main app pages
│   │   ├── layout.tsx            # Root layout
│   │   ├── page.tsx              # Home page
│   │   ├── search/               # Search results
│   │   └── movie/[id]/           # Movie details
│   └── api/                      # API routes
│       ├── search/route.ts       # Search endpoint
│       ├── movie/[id]/route.ts   # Movie details API
│       └── cron/                 # Cron jobs
│           └── daily-sync/       # Daily scraping pipeline
├── components/                   # React components
│   ├── search/                   # Search components
│   ├── movie/                    # Movie components
│   └── ui/                       # shadcn/ui components
├── lib/                          # Core libraries
│   ├── wikipedia/                # Wikipedia API client
│   ├── scraper/                  # News scraper
│   ├── search/                   # Meilisearch client
│   ├── db/                       # Database queries
│   └── utils/                    # Utility functions
├── supabase/
│   └── migrations/               # Database migrations
├── public/                       # Static assets
├── docker-compose.yml            # Meilisearch setup
├── next.config.js                # Next.js config
├── tailwind.config.ts            # Tailwind config
└── package.json                  # Dependencies

API Endpoints

Public Endpoints

GET /api/search?q={query}

Search for movies with autocomplete

Query Parameters:

  • q - Search query (min 2 characters)
  • page - Page number (default: 1)
  • perPage - Results per page (default: 20)
  • platforms - Filter by platforms (comma-separated)
  • languages - Filter by languages (comma-separated)
  • genres - Filter by genres (comma-separated)

Response:

{
  "hits": [
    {
      "document": {
        "id": "uuid",
        "title": "Movie Name",
        "year": 2024,
        "platforms": ["netflix", "prime_video"]
      }
    }
  ],
  "found": 150,
  "page": 1
}

GET /api/movie/{id}

Get detailed movie information

Response:

{
  "movie": {
    "id": "uuid",
    "title": "Movie Name",
    "year": 2024,
    "plot": "...",
    "director": "Director Name",
    "cast": [...],
    "ott_availability": [...]
  }
}

Protected Endpoints (Require CRON_SECRET)

GET /api/cron/daily-sync?secret={CRON_SECRET}

Trigger the daily scraping pipeline

Response:

{
  "success": true,
  "scraping": {
    "totalArticles": 100,
    "processedArticles": 50,
    "successfulExtractions": 25
  },
  "matching": {
    "matchedCount": 20,
    "unmatchedCount": 5
  }
}

Database Schema

Movies Table

  • id - UUID (primary key)
  • wikipedia_title - Wikipedia page title
  • title - Movie title
  • year - Release year
  • director - Director name(s)
  • plot - Movie plot summary
  • genres - Array of genres
  • poster_url - Poster image URL
  • primary_language - Main language code

OTT Availability Table

  • movie_id - Reference to movie
  • platform - OTT platform enum
  • is_available - Currently available boolean
  • available_since - Availability start date
  • source_url - News article source
  • source_name - Source website

Scraped Articles Table

  • url - Article URL
  • source_name - Source website
  • title - Article title
  • processed - Whether extraction was successful
  • extracted_movies - JSON array of extracted movies

Troubleshooting

Meilisearch Connection Issues

Problem: Can't connect to Meilisearch

Solutions:

  1. Verify Docker is running: docker ps
  2. Check Meilisearch logs: docker logs justott-meilisearch
  3. Verify MEILISEARCH_HOST in .env matches your setup
  4. Check firewall settings

Supabase Connection Issues

Problem: Database queries failing

Solutions:

  1. Verify SUPABASE_URL is correct
  2. Check API keys haven't expired
  3. Ensure migrations have been run
  4. Check Row Level Security policies

Scraping Not Working

Problem: Cron job returns no results

Solutions:

  1. Verify ZAI_API_KEY or OPENAI_API_KEY is set
  2. Check RSS feeds are accessible
  3. Check logs for specific errors
  4. Try running manually with debug output

Build Errors

Problem: npm run build fails

Solutions:

  1. Delete node_modules and .next folders
  2. Run npm install again
  3. Ensure all environment variables are set (even if using defaults)
  4. Check for TypeScript errors: npm run type-check

Cost Estimates

Monthly Costs (Free Tier Options)

Service Free Tier Paid Tier
Vercel Hosting 100GB bandwidth $20/month
Supabase Database 500MB storage $25/month
Meilisearch Cloud 14 days trial $36/month
Total (Self-hosted) $0/month $20/month
Total (Cloud) $0/month ~$81/month

LLM API Costs

Based on z.ai/OpenAI pricing:

  • GPT-4o-mini: ~$0.15 per 1M tokens
  • Estimated: 100 articles ≈ 200K tokens ≈ $0.03
  • Monthly estimate (1000 articles): ~$0.30

To reduce costs:

  • Run scraper less frequently (weekly instead of daily)
  • Use smaller models (GPT-4o-mini instead of GPT-4)
  • Self-host Meilisearch instead of using cloud
  • Use rule-based extraction fallback

Contributing

Contributions are welcome! Please follow these steps:

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature/my-feature
  3. Make your changes
  4. Run tests: npm run test
  5. Commit changes: git commit -am 'Add new feature'
  6. Push to branch: git push origin feature/my-feature
  7. Submit a pull request

License

This project is open source and available under the MIT License.

Acknowledgments

  • Wikipedia - For providing free movie data
  • Meilisearch - For the excellent open-source search engine
  • Supabase - For the amazing PostgreSQL hosting
  • shadcn - For the beautiful UI components

Support

Roadmap

  • Add TV show support
  • User watchlist functionality
  • Email notifications for OTT releases
  • Mobile app (React Native)
  • Regional language support for UI
  • Advanced filtering options
  • User reviews and ratings

Made with ❤️ for Indian cinema lovers

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors