Skip to content

Repository files navigation

🎬 CineTrack

A local-first desktop application for discovering, organising, and tracking films and TV series.

Tauri React TypeScript pnpm License: MIT

CineTrack is a local-first desktop application built with Tauri, React, TypeScript, and SQLite. It uses the TMDB catalogue to explore films and TV series while keeping your watchlist, viewing progress, and activity history on your device.

Note

The interface is available in English and French, with the internationalisation architecture in place for adding more languages.

✨ Features

Discover

  • Browse popular, top-rated, currently airing, and upcoming films and TV series.
  • Explore the catalogue by genre and streaming provider, or get a random pick with "Watch tonight".
  • Search films and TV series together, with filters by media type.
  • View detailed media pages with synopses, cast members, genres, status, trailers, recommendations, and streaming availability by region.

Organise

  • Add films and TV series to your watchlist, a unified library (planned/watching/completed/dropped/rewatching), or custom lists.
  • Filter and sort your watchlist and library by media type, status, date, title, or rating.
  • Mark films as watched or unwatched, rate and tag titles, and mark favourites.
  • Review recent actions in a local activity timeline.
  • Manage multiple local profiles, each with its own watchlist, library, and history.

Track TV series

  • Mark individual episodes as watched or unwatched.
  • Mark an entire season or series at once.
  • View overall and season-by-season progress.
  • Quickly resume series already in progress from the home page.
  • Get notified when a release date or new episode is coming up via the calendar, and set streaming-availability alerts.

Personalise

  • Switch between light and dark themes and several accent colours.
  • Enable compact mode or reduced motion.
  • Set default filters for search and the watchlist.
  • Sign in with Supabase (email OTP or social OAuth) when account sync is configured; the app otherwise works fully offline with a local-only profile.
  • Review viewing statistics and a yearly "wrapped" summary.

🧱 Technology stack

Area Technologies
Desktop application Tauri 2, Rust
Frontend React 19, TypeScript, Vite
Styling and components Tailwind CSS, Radix UI, local components inspired by shadcn/ui
Routing TanStack Router
Remote data TanStack Query, TMDB API
Optional account sync Supabase Auth (email OTP, OAuth)
Desktop persistence SQLite through @tauri-apps/plugin-sql, Stronghold for secrets
UI state Zustand
Validation Zod
Internationalisation i18next, react-i18next (English, French)
Animation and icons Framer Motion, Lucide React
Testing Vitest, Testing Library, cargo test

πŸ—οΈ Architecture

The remote catalogue and personal data are deliberately kept separate:

flowchart LR
    UI[React UI] --> Q[TanStack Query]
    Q --> MP[MediaProvider]
    MP --> TMDB[TMDB API]

    UI --> LR[Local repositories]
    LR --> DB[(SQLite app.db)]
Loading
  • MediaProvider abstracts catalogue access, making it possible to replace TMDB without coupling the interface to its API.
  • Local repositories (one per domain: watchlist, library, progress, history, preferences, profiles, collections, availability, stats) manage personal data, all of it in SQLite (sqlite:app.db).
  • SQLite is only reachable from inside the Tauri webview β€” a plain browser tab has no access to Tauri's IPC bridge, even when it's pointed at the same dev server pnpm tauri dev uses. Every local-data hook already tolerates a failed query (none use React Query's suspense mode), so the UI still renders outside Tauri for layout/styling work; reads/writes to SQLite just fail silently. A small non-blocking banner flags this, see src/components/desktop/browser-preview-banner.tsx.

πŸ“¦ Prerequisites

Before getting started, install:

Check that your environment is ready:

node --version
pnpm --version
rustc --version
cargo --version

πŸš€ Installation

1. Clone the repository

git clone https://github.com/Arrows78/cinetrack.git
cd cinetrack

2. Install dependencies

corepack enable
pnpm install

3. Configure TMDB

Copy the example environment file:

cp .env.example .env

Then add your token to .env:

VITE_TMDB_API_TOKEN=your_tmdb_bearer_token_here

The application expects the TMDB API Read Access Token, which is sent as a Bearer token to the TMDB API.

Security note: VITE_TMDB_API_TOKEN is inlined by Vite into the frontend bundle at build time. Keep it set in .env only for local/web development. Never set it when producing a desktop bundle for distribution (pnpm tauri build) β€” a value present at that time would ship in cleartext inside the built binary, bypassing the Stronghold vault. Distributed builds should rely solely on the in-app token vault (Settings β†’ TMDB) or leave the variable unset.

4. (Optional) Configure Supabase account sync

CineTrack works fully offline with VITE_AUTH_REQUIRED=false (the default). To enable account sign-in (email OTP or social OAuth), follow docs/auth.md for the full Supabase project setup, redirect URLs, and provider configuration.

5. Start the desktop application

pnpm tauri dev

This command starts the Vite server on port 1420, initialises the SQLite database, and opens the Tauri window.

🌐 About pnpm dev

pnpm dev (used internally by pnpm tauri dev to serve the frontend, and also runnable on its own) starts the same Vite server on http://localhost:1420 β€” but CineTrack's only persistence layer is SQLite, reachable exclusively from inside the Tauri webview. A plain browser tab has no access to Tauri's IPC bridge, even when it's pointed at that same URL while pnpm tauri dev is running.

Note

Opening http://localhost:1420 outside the Tauri window β€” pnpm dev on its own, or a regular browser tab while pnpm tauri dev runs β€” still renders the full UI (useful for quick layout/styling iteration), with a small banner flagging that SQLite reads/writes won't work. Use the Tauri window (pnpm tauri dev) or the installed desktop application whenever you need real data.

πŸ› οΈ Scripts

Command Description
pnpm dev Starts the Vite development server.
pnpm build Checks TypeScript types and creates the frontend production build.
pnpm preview Serves the Vite production build locally.
pnpm lint Analyses the project with ESLint.
pnpm format Formats files with Prettier.
pnpm test Runs the Vitest test suite.
pnpm test:coverage Runs the test suite with a coverage report.
pnpm typecheck Checks TypeScript types without emitting output.
pnpm tauri dev Starts the desktop application in development mode.
pnpm tauri build Creates desktop bundles for the current platform.

For the Rust side, run cargo check --manifest-path src-tauri/Cargo.toml and cargo test --manifest-path src-tauri/Cargo.toml (both also run in CI).

Generated Tauri bundles are written to src-tauri/target/release/bundle/.

πŸ“‚ Project structure

cinetrack/
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ app/                    # Application setup, router, and QueryClient
β”‚   β”œβ”€β”€ components/             # Presentational UI: layout, media, ui/, states/, settings, collections, desktop, library
β”‚   β”œβ”€β”€ db/                     # SQLite connection and migrations (shared by every feature)
β”‚   β”œβ”€β”€ features/                # One folder per domain, each bundling its repository/service with the hooks that use it
β”‚   β”‚   β”œβ”€β”€ auth/                #   Supabase session, OAuth, email OTP
β”‚   β”‚   β”œβ”€β”€ availability/        #   Streaming-availability alerts and background monitor
β”‚   β”‚   β”œβ”€β”€ backup/              #   Portable JSON export/import, automatic backups
β”‚   β”‚   β”œβ”€β”€ calendar/            #   Release and episode calendar
β”‚   β”‚   β”œβ”€β”€ collections/         #   Profiles and custom lists
β”‚   β”‚   β”œβ”€β”€ desktop/             #   Tray/deep-link wiring, updater, notifications, TMDB token vault
β”‚   β”‚   β”œβ”€β”€ history/              #   Local activity timeline
β”‚   β”‚   β”œβ”€β”€ library/              #   Unified watch status, ratings, tags
β”‚   β”‚   β”œβ”€β”€ media/                #   TMDB client + MediaProvider, search/discovery hooks, image cache
β”‚   β”‚   β”œβ”€β”€ preferences/          #   Theme, language, region, and other user settings
β”‚   β”‚   β”œβ”€β”€ progress/              #   Movie/episode watched state and series progress
β”‚   β”‚   β”œβ”€β”€ stats/                #   Viewing statistics and yearly wrap-up
β”‚   β”‚   β”œβ”€β”€ watch-tonight/        #   Random pick service
β”‚   β”‚   └── watchlist/             #   Watchlist repository and hooks
β”‚   β”œβ”€β”€ hooks/                   # Generic, repository-free hooks (debounce, confetti)
β”‚   β”œβ”€β”€ i18n/                    # Internationalisation setup and translations
β”‚   β”œβ”€β”€ pages/                   # Route components composed from feature hooks
β”‚   β”œβ”€β”€ shared/                  # Configuration, constants, and utilities
β”‚   β”œβ”€β”€ store/                   # Lightweight global state with Zustand
β”‚   β”œβ”€β”€ styles/                  # Global styles and themes
β”‚   └── types/                   # Domain models
β”œβ”€β”€ src-tauri/
β”‚   β”œβ”€β”€ capabilities/           # Tauri permissions
β”‚   β”œβ”€β”€ src/
β”‚   β”‚   β”œβ”€β”€ commands/           # Tauri commands (TMDB proxy, updater config check)
β”‚   β”‚   β”œβ”€β”€ tray.rs              # System tray icon and menu
β”‚   β”‚   β”œβ”€β”€ lib.rs                # Plugin registration and app bootstrap
β”‚   β”‚   └── main.rs
β”‚   β”œβ”€β”€ Cargo.toml              # Rust dependencies
β”‚   └── tauri.conf.json         # Desktop configuration and bundle settings
β”œβ”€β”€ .env.example
β”œβ”€β”€ package.json
└── README.md

πŸ’Ύ Local persistence

CineTrack does not require a user account or an application server to save personal data.

The SQLite schema (a single migration, see src/db/migrations/001-initial-schema.ts) includes:

  • profiles, preferences;
  • watchlist_items, library_items, viewing_events, seen_movies, episode_progress, tracked_series;
  • custom_lists, custom_list_items;
  • availability_alerts, availability_snapshots;
  • activity_log.

Every table (other than preferences and the pure-cache availability_snapshots) has an internal id INTEGER PRIMARY KEY β€” a storage-engine-only rowid never surfaced outside SQL β€” plus a public uuid TEXT UNIQUE that the app treats as .id, and created_at/updated_at timestamps. See docs/database-schema.html for the full diagram.

Catalogue data, posters, and metadata are loaded from TMDB, so they require an internet connection and a valid API token.

πŸ—ΊοΈ Roadmap

  • Code-split the frontend bundle (the main chunk currently exceeds Vite's 500 kB warning threshold).
  • Add more translations beyond English and French.

πŸ™Œ Contributing

Issues and pull requests are welcome, whether you are fixing a bug, improving the documentation, or proposing a feature.

Before submitting a change, run:

pnpm validate

This chains lint, format:check, typecheck, test, build, and the Rust cargo check/clippy/test β€” the same checks CI runs.

🎞️ TMDB attribution

CineTrack uses data and images provided by TMDB.

This product uses the TMDB API but is not endorsed or certified by TMDB.

Review the TMDB documentation and attribution requirements before publicly distributing or commercially using the application.

πŸ“„ License

MIT β€” see LICENSE.

About

A premium desktop app to track movies, TV shows, watchlists and episode progress, powered by TMDB and built with Tauri, React and SQLite.

Topics

Resources

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages