Files
stream-capture/spec/prd.md
Julian Freeman a18065de93 first
2025-12-02 09:11:59 -04:00

6.5 KiB

Project: StreamCapture (Tauri + Vue 3 YouTube Downloader)

1. Context & Objective

You are an expert Full-Stack Rust/TypeScript developer specializing in Tauri v2 application development. Your task is to build a cross-platform (Windows & macOS) desktop application named "StreamCapture" in the current directory. The app is a GUI wrapper for yt-dlp, but unlike standard sidecar implementations, it must manage the yt-dlp binary externally (in the user's AppData directory) to allow for frequent updates without rebuilding the app.

Tech Stack:

  • Core: Tauri v2 (Rust)
  • Frontend: Vue 3 (Composition API, <script setup>)
  • Build Tool: Vite
  • Styling: Tailwind CSS (Mobile-first, Modern UI)
  • State Management: Pinia
  • Icons: Lucide-vue-next
  • HTTP Client (Rust): reqwest (for downloading yt-dlp)

2. Core Architecture & Workflow

2.1. External Binary Management (Crucial)

Since yt-dlp updates frequently, we do NOT bundle it inside the binary.

  1. Location: The app must utilize the system's local data directory (e.g., %APPDATA%/StreamCapture/bin on Windows, ~/Library/Application Support/StreamCapture/bin on macOS).
  2. Initialization: On app launch, the Rust backend must check if yt-dlp exists in that directory.
  3. Auto-Download: If missing, download the correct binary from the official GitHub releases (yt-dlp.exe for Win, yt-dlp_macos for Mac).
  4. Permissions: On macOS, apply chmod +x (0o755) to the downloaded binary immediately.
  5. Execution: Use Rust's std::process::Command to execute this specific binary using its absolute path.

2.2. Configuration Persistence

  • File: settings.json in the app data directory.
  • Fields:
    • download_path: string (Default: System Download Dir)
    • theme: 'light' | 'dark' | 'system' (Default: system)
    • last_updated: timestamp (for yt-dlp check)

2.3. History Persistence

  • File: history.json.
  • Stores a list of completed or failed downloads (metadata, status, timestamp, file path).

3. Rust Backend Specifications (src-tauri/src/lib.rs & Modules)

Create specific commands to handle logic securely. Avoid exposing raw shell execution to the frontend.

Module: ytdlp_manager

  • init_ytdlp(): Checks existence. If missing, downloads it. Returns status.
  • update_ytdlp(): Runs yt-dlp -U.
  • get_version(): Returns current version string.

Module: downloader

  • fetch_metadata(url: String):
    • Runs yt-dlp --dump-single-json --flat-playlist [url].
    • Logic: If it's a playlist, return a list of video objects (id, title, thumbnail, duration). If single video, return one object.
    • Important: Do NOT download media yet.
  • download_video(url: String, options: DownloadOptions):
    • Options Struct: { is_audio_only: bool, quality: String, output_path: String }
    • Process: Spawns a command. Emits Tauri Events (download-progress) to frontend with percentage and speed.

Module: storage

  • Helper functions to read/write settings.json and history.json.

4. Frontend Specifications (Vue 3 + Tailwind)

4.1. UI Layout

  • Sidebar: Navigation (Home/Download, History, Settings).
  • Header: Theme toggle, App status (checking yt-dlp...).
  • Main Content: Dynamic view based on route.

4.2. Views

A. Home View (The Downloader)

  1. Input Area: Large, modern input box for URL. "Analyze" button.
  2. Selection Area (Conditional):
    • Appears after "Analyze" succeeds.
    • Shows thumbnail(s) and title(s).
    • If Playlist: Show list of items with checkboxes (Select All / Select None).
  3. Options Panel:
    • Format: Dropdown (Best Video+Audio, 1080p, 720p, 480p).
    • Mode: Toggle Switch (Video / Audio Only).
  4. Action: Big "Download" button.
  5. Progress: Progress bars for active downloads.

B. History View

  • Table/List of past downloads.
  • Columns: Thumbnail (small), Title, Date, Format, Status (Success/Fail).
  • Actions: "Open File Location", "Delete Record" (Icon), "Clear All" (Button at top).

C. Settings View

  • Download Path: Input field + "Browse" button (use Tauri dialog API).
  • Yt-dlp: Show current version. Button "Check for Updates".
  • Theme: Radio buttons (Light/Dark/System).

4.3. State Management (Pinia stores)

  • useSettingsStore: Loads/saves config. Handles theme applying (adding .dark class to html).
  • useQueueStore: Manages active downloads and progress events.

5. Visual Design Guidelines (Tailwind)

  • Theme:
    • Light Mode: White/Gray-50 background, Zinc-900 text, Primary Blue-600.
    • Dark Mode: Zinc-950 background, Gray-100 text, Primary Blue-500.
  • Components:
    • Rounded corners (rounded-xl).
    • Subtle shadows (shadow-sm, shadow-md).
    • Input fields with focus rings.
    • Transitions for hover states and page switches.

6. Implementation Steps for Gemini

Please generate the code in the following order. Ensure all files include // filepath: ... comments.

  1. Rust Setup:
    • Cargo.toml (dependencies: reqwest, serde, serde_json, tokio, etc.).
    • src-tauri/src/lib.rs: Main entry with command registration.
    • src-tauri/src/ytdlp.rs: The download/update logic.
    • src-tauri/src/commands.rs: The Tauri commands exposed to frontend.
  2. Frontend Setup:
    • package.json: deps (pinia, vue-router, lucide-vue-next, tailwindcss, autoprefixer, postcss).
    • src/style.css: Tailwind directives.
    • src/stores/...: Pinia stores.
    • src/components/...: Reusable UI components (Input, Button, Card).
    • src/views/...: The main pages.
    • src/App.vue: Main layout.
  3. Configuration:
    • tailwind.config.js: Dark mode config.
    • src-tauri/capabilities/default.json: CRITICAL. Configure permissions to allow accessing app_data_dir and the network scope.

7. Testing Requirements

  • Create a basic Rust test in src-tauri/src/ytdlp.rs that verifies it can construct the correct path for the binary based on OS.
  • Ensure Vue components handle "Loading" states gracefully (skeletons or spinners).

IMPORTANT NOTE ON PERMISSIONS: Since we are using std::process::Command directly in Rust, we do not need to configure the strict shell scope in tauri.conf.json, but we MUST ensure the App Data directory is writable.

Start by generating the Rust backend logic first, as the frontend depends on these commands.