This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
GrabZilla 2.1 is an Electron-based desktop application for downloading YouTube and Vimeo videos with professional video management. It features smart URL parsing, cookie file support for age-restricted content, and local binary management (yt-dlp and ffmpeg) for reliable video downloading and conversion.
./binaries/yt-dlp and ./binaries/ffmpegyt-dlp or ffmpeg commands.exe on Windows: process.platform === 'win32' ? '.exe' : ''CRITICAL FOR AI SWITCHING: Use when preparing to hand off to a DIFFERENT AI system (GPT-4, Gemini, local LLMs, etc.)
Purpose: Creates universal, AI-agnostic handoff documentation that ANY AI can understand, regardless of context window size or capabilities.
When to trigger:
What it creates:
Key principle: Assume target AI knows NOTHING about this project, Electron, yt-dlp, or previous sessions.
ALWAYS USE PROACTIVELY after ANY code changes, feature implementations, or optimizations.
When to trigger (AUTOMATIC):
Agent responsibilities:
HANDOFF_NOTES.md with session detailsCLAUDE.md if architecture/patterns changedOPTIMIZATION_SUMMARY.md)TODO.md with completed tasksUsage pattern:
// After completing work, ALWAYS invoke:
Task({
subagent_type: "general-purpose", // or create dedicated doc-keeper agent
description: "Update all documentation",
prompt: `I just completed [describe work]. Please:
1. Update HANDOFF_NOTES.md with:
- Current session summary (what was done)
- Files modified/created list
- Performance metrics if applicable
- Next steps for continuation
2. Update CLAUDE.md if:
- Architecture patterns changed
- New critical rules added
- Performance guidelines updated
3. Create [FEATURE_NAME]_SUMMARY.md with:
- Complete technical details
- Before/after comparisons
- Benchmark results
- Lessons learned
4. Update TODO.md:
- Mark completed tasks as done
- Add any new tasks discovered
Files modified: [list]
Performance gains: [metrics]
Key decisions: [decisions]`
})
Example (Metadata Optimization): After optimizing metadata extraction, the agent automatically:
Key Files to Maintain:
HANDOFF_NOTES.md - Session log and current statusCLAUDE.md - Development guidelines and patternsTODO.md - Task tracking and progress*_SUMMARY.md - Feature/optimization documentationREADME.md - User-facing documentation (when needed)Documentation Standards:
This project has several MCP (Model Context Protocol) servers configured to enhance development capabilities:
Purpose: Documentation lookup for libraries and APIs
Available Tools:
resolve-library-id - Find library IDs for documentationget-library-docs - Get comprehensive documentation for librariesWhen to use:
child_process.spawn, execFile)Example queries:
Purpose: Structured reasoning for complex technical decisions
Available Tools:
sequentialthinking - Multi-step reasoning with explicit thought processMandatory use for:
Decision frameworks:
Purpose: Persistent context and learning across sessions
Available Tools:
search_nodes - Search stored context and relationshipscreate_entities - Store important project informationadd_observations - Record decisions and patternsUse for:
Purpose: Extract design specifications and generate implementation code
Available Tools:
get_metadata - Get design structure and node IDs (auto-approved)get_code - Generate implementation code from designsget_variable_defs - Extract design tokens (colors, spacing, typography)get_screenshot - Visual reference for validationProject Figma Reference:
5:461 (GrabZilla2.0_UI)5:4635:4835:5375:825When to use:
Purpose: Automated browser testing and validation
Available Tools:
navigate - Open URLs in automated browserscreenshot - Capture visual statesclick - Simulate user interactionsget_clickable_elements - Identify interactive elementsget_markdown / get_text - Extract contentUse for:
# Setup and dependencies
npm install # Install dependencies
npm run setup # Download required binaries (yt-dlp and ffmpeg)
# Development
npm run dev # Run in development mode (with DevTools)
npm start # Run in production mode
# Testing
npm test # Run all tests sequentially
npm run test:ui # Run tests with Vitest UI
npm run test:unit # Run unit tests only
npm run test:validation # Run URL validation tests
npm run test:components # Run component tests
# Building
npm run build # Build for current platform
npm run build:mac # Build macOS DMG
npm run build:win # Build Windows NSIS installer
npm run build:linux # Build Linux AppImage
GrabZilla follows Electron's standard multi-process architecture:
src/main.js): System integration, IPC handlers, binary execution, file system operationssrc/preload.js): Secure bridge using contextBridge to expose limited APIs to rendererscripts/app.js): UI logic, state management, user interactionsALWAYS use local binaries - never rely on system PATH binaries:
// ✅ CORRECT: Use local binaries with platform detection
const getBinaryPath = (name) => {
const ext = process.platform === 'win32' ? '.exe' : '';
return `./binaries/${name}${ext}`;
};
const ytdlp = spawn(getBinaryPath('yt-dlp'), args);
// ❌ WRONG: Never use system PATH binaries
const ytdlp = spawn('yt-dlp', args);
All binary execution must:
getBinaryPath() helper for platform-specific pathsThe application uses a centralized state management pattern in scripts/utils/state-manager.js:
const app = {
videos: [], // Array of video objects
config: { // User preferences
quality: '720p',
format: 'mp4',
savePath: '',
cookieFile: null
},
ui: { // UI state
isDownloading: false,
selectedVideos: []
}
};
Video objects follow a specific model structure defined in scripts/models/Video.js with status states: ready, downloading, converting, completed, error.
The main process handles all system operations via IPC channels defined in src/preload.js:
select-save-directory, select-cookie-filecheck-binary-dependencies, check-binary-versionsdownload-video, get-video-metadatacancel-conversion, cancel-all-conversions, get-active-conversionsshow-notification, show-error-dialog, show-info-dialogdownload-progress (via ipcRenderer.on)Video downloads follow a two-stage pipeline when format conversion is required:
The conversion logic is in scripts/utils/ffmpeg-converter.js and integrates with the download handler in src/main.js:downloadWithYtDlp() and convertVideoFormat().
All user inputs must be validated before passing to binaries to prevent command injection:
scripts/utils/url-validator.js before passing to yt-dlpCRITICAL: Cookie files must be used for BOTH metadata extraction AND video downloads.
Architecture:
window.appState.config.cookieFile--cookies flagImplementation Pattern:
// ✅ CORRECT: Retrieve cookie file from app state
const cookieFile = window.appState?.config?.cookieFile || null
// Pass to IPC calls
await window.ipcAPI.getVideoMetadata(url, cookieFile)
await window.ipcAPI.getBatchVideoMetadata(urls, cookieFile)
// Main process adds to yt-dlp args if present
if (cookieFile && fs.existsSync(cookieFile)) {
args.unshift('--cookies', cookieFile)
}
Use Cases:
Why This Matters:
The app uses Electron security best practices:
nodeIntegration: falsecontextIsolation: trueenableRemoteModule: falsecontextBridgedownload-progress IPC channel{ url, progress, status, stage, message }The app follows Apple's Human Interface Guidelines with a dark theme. All styling uses CSS custom properties defined in styles/main.css:
/* Primary Colors */
--primary-blue: #155dfc;
--success-green: #00a63e;
--error-red: #e7000b;
/* Backgrounds */
--bg-dark: #1d293d;
--header-dark: #0f172b;
--card-bg: #314158;
--border-color: #45556c;
/* Text */
--text-primary: #ffffff;
--text-secondary: #cad5e2;
--text-muted: #90a1b9;
--text-disabled: #62748e;
Tests are organized into suites run sequentially to avoid memory issues:
The custom test runner (run-tests.js) runs test suites sequentially with memory cleanup between runs.
Supported video sources:
youtube.com/watch?v=*, youtu.be/*, youtube.com/playlist?list=*vimeo.com/[id], player.vimeo.com/video/[id]URL validation regex patterns are in scripts/utils/url-validator.js. The app extracts URLs from multi-line pasted text with deduplication.
IMPORTANT: Only extract the 3 fields actually displayed in UI (70% less data, faster performance)
Fields displayed:
title - Video name shown in listduration - MM:SS format in Duration columnthumbnail - 16x12 preview imageOptimized yt-dlp command:
// CORRECT: Extract only required fields (5-10x faster)
const args = [
'--print', '%(title)s|||%(duration)s|||%(thumbnail)s',
'--no-warnings',
'--skip-download',
'--playlist-items', '1',
'--no-playlist',
url
]
// Parse pipe-delimited output
const [title, duration, thumbnail] = output.trim().split('|||')
DO NOT extract these unused fields:
uploader, uploadDate, viewCount, description - Not displayed in UIavailableQualities - Quality dropdown is manual, not auto-populatedfilesize - Not shown to userplatform - Not displayedBatch Processing (RECOMMENDED):
Always use get-batch-video-metadata for multiple URLs (10-15% faster):
// Batch format: URL|||title|||duration|||thumbnail (one per line)
const args = [
'--print', '%(webpage_url)s|||%(title)s|||%(duration)s|||%(thumbnail)s',
'--no-warnings',
'--skip-download',
'--ignore-errors',
'--playlist-items', '1',
'--no-playlist',
...urls // All URLs in single command
]
Performance benefits:
// YouTube URL patterns
const youtubeRegex = /(?:https?:\/\/)?(?:www\.)?(?:youtube\.com\/(?:[^\/\n\s]+\/\S+\/|(?:v|e(?:mbed)?)\/|\S*?[?&]v=)|youtu\.be\/)([a-zA-Z0-9_-]{11})/g;
// Vimeo URL patterns
const vimeoRegex = /(?:https?:\/\/)?(?:www\.)?(?:vimeo\.com\/|player\.vimeo\.com\/video\/)(\d+)/g;
// Playlist patterns
const playlistRegex = /(?:https?:\/\/)?(?:www\.)?youtube\.com\/playlist\?list=([a-zA-Z0-9_-]+)/g;
Error handling is centralized in scripts/utils/error-handler.js and provides user-friendly messages:
The main process function parseDownloadError() in src/main.js maps yt-dlp error output to specific error types with actionable suggestions.
The app supports macOS, Windows, and Linux:
.exe on Windows)titleBarStyle: 'hiddenInset')dialog moduleNotification API with fallback to node-notifierThe electron-builder configuration in package.json includes:
dist/src/, assets/, binaries/, styles/, scripts/, index.htmlWhen a file exceeds 300 lines, split into logical modules:
scripts/
├── app.js // Main application entry (< 100 lines)
├── components/ // UI component logic
├── utils/ // Utility functions
├── models/ // Data models
└── constants/ // Configuration constants
Every function MUST include JSDoc comments:
/**
* Downloads a video using yt-dlp binary with specified quality and format
* @param {Object} video - Video object containing url, quality, format
* @param {string} savePath - Directory path for downloaded file
* @param {Function} progressCallback - Called with download progress (0-100)
* @returns {Promise<Object>} Download result with success status and file path
* @throws {Error} When binary not found or download fails
*/
downloadVideo, validateUrl)videoQueue, downloadProgress)MAX_CONCURRENT_DOWNLOADS, DEFAULT_QUALITY)VideoManager, DownloadQueue)video-manager.js, url-parser.js)// Mandatory state structure - do not deviate
const appState = {
videos: [], // Array of video objects with id, url, title, status
config: {
quality: '720p', // Default quality setting
format: 'mp4', // Default output format
savePath: '', // User-selected download directory
cookieFile: null // Path to cookie file for auth
},
ui: {
isDownloading: false, // Global download state
selectedVideos: [], // Currently selected video IDs
updateAvailable: false // Binary update status
}
};