initial commit
This commit is contained in:
58
docs/AGENTS.md
Normal file
58
docs/AGENTS.md
Normal file
@@ -0,0 +1,58 @@
|
||||
# Agent Instructions
|
||||
|
||||
## Documentation Guidelines
|
||||
|
||||
When adding new features or making significant changes to this project, please follow these documentation guidelines:
|
||||
|
||||
### 1. Feature Documentation
|
||||
- **Always document new features** in markdown files within the `docs/` directory
|
||||
- Use descriptive filenames that match the feature (e.g., `youtube-downloader.md`, `transcoding.md`)
|
||||
- Include the following sections in feature documentation:
|
||||
- **Overview**: What the feature does
|
||||
- **Usage**: How to use the feature
|
||||
- **Technical Details**: Implementation details, APIs used, dependencies
|
||||
- **Configuration**: Any configuration options or environment variables
|
||||
- **Examples**: Code examples or usage examples
|
||||
|
||||
### 2. Documentation Structure
|
||||
- Keep documentation files focused on a single feature or topic
|
||||
- Use clear headings and formatting
|
||||
- Include code examples where relevant
|
||||
- Link between related documentation files when appropriate
|
||||
|
||||
### 3. When to Document
|
||||
- Adding a new feature
|
||||
- Adding a new API endpoint
|
||||
- Adding a new configuration option
|
||||
- Making significant changes to existing features
|
||||
- Adding new dependencies or tools
|
||||
|
||||
### 4. File Naming Convention
|
||||
- Use kebab-case for filenames (e.g., `youtube-downloader.md`)
|
||||
- Be descriptive but concise
|
||||
- Group related features in the same file when appropriate
|
||||
|
||||
### 5. Update Existing Documentation
|
||||
- When modifying existing features, update the relevant documentation file
|
||||
- If a feature is removed, mark it as deprecated or remove the documentation
|
||||
|
||||
## Example Documentation Template
|
||||
|
||||
```markdown
|
||||
# Feature Name
|
||||
|
||||
## Overview
|
||||
Brief description of what this feature does.
|
||||
|
||||
## Usage
|
||||
How to use this feature.
|
||||
|
||||
## Technical Details
|
||||
Implementation details, APIs, dependencies.
|
||||
|
||||
## Configuration
|
||||
Any configuration options.
|
||||
|
||||
## Examples
|
||||
Code or usage examples.
|
||||
```
|
||||
84
docs/README.md
Normal file
84
docs/README.md
Normal file
@@ -0,0 +1,84 @@
|
||||
# Documentation Index
|
||||
|
||||
Welcome to the Downlink documentation! This directory contains comprehensive documentation for the YouTube downloader application.
|
||||
|
||||
## Documentation Files
|
||||
|
||||
### Getting Started
|
||||
- **[Setup Guide](./setup.md)** - Installation, configuration, and troubleshooting
|
||||
- **[README.md](../README.md)** - Project overview and quick start
|
||||
|
||||
### Feature Documentation
|
||||
- **[YouTube Downloader](./youtube-downloader.md)** - Core download feature documentation
|
||||
- **[Transcoding](./transcoding.md)** - Format conversion and transcoding details
|
||||
- **[Features](./features.md)** - Complete feature list and roadmap
|
||||
|
||||
### Technical Documentation
|
||||
- **[API Documentation](./api.md)** - API endpoints, requests, and responses
|
||||
- **[Architecture](./architecture.md)** - System architecture and design decisions
|
||||
- **[Configuration](./configuration.md)** - Environment variables and configuration options
|
||||
|
||||
### Contributing
|
||||
- **[Agent Instructions](./AGENTS.md)** - Guidelines for documenting new features
|
||||
|
||||
## Quick Links
|
||||
|
||||
### For Users
|
||||
- Start with the [Setup Guide](./setup.md)
|
||||
- Learn about features in [Features](./features.md)
|
||||
- Check [YouTube Downloader](./youtube-downloader.md) for usage details
|
||||
|
||||
### For Developers
|
||||
- Read [Architecture](./architecture.md) for system overview
|
||||
- Check [API Documentation](./api.md) for endpoint details
|
||||
- Follow [Agent Instructions](./AGENTS.md) when adding features
|
||||
|
||||
### For Contributors
|
||||
- Follow [Agent Instructions](./AGENTS.md) for documentation standards
|
||||
- Update relevant docs when adding/modifying features
|
||||
- Keep documentation in sync with code changes
|
||||
|
||||
## Documentation Standards
|
||||
|
||||
When adding or updating documentation:
|
||||
|
||||
1. **Use clear headings** - Organize content with proper markdown headings
|
||||
2. **Include examples** - Provide code examples and usage scenarios
|
||||
3. **Keep it updated** - Update docs when features change
|
||||
4. **Be comprehensive** - Cover overview, usage, technical details, and examples
|
||||
5. **Link related docs** - Cross-reference related documentation
|
||||
|
||||
## Document Structure Template
|
||||
|
||||
Each feature document should include:
|
||||
|
||||
```markdown
|
||||
# Feature Name
|
||||
|
||||
## Overview
|
||||
Brief description
|
||||
|
||||
## Usage
|
||||
How to use
|
||||
|
||||
## Technical Details
|
||||
Implementation details
|
||||
|
||||
## Configuration
|
||||
Settings and options
|
||||
|
||||
## Examples
|
||||
Code examples
|
||||
|
||||
## Limitations
|
||||
Known limitations
|
||||
|
||||
## Future Improvements
|
||||
Planned enhancements
|
||||
```
|
||||
|
||||
## Need Help?
|
||||
|
||||
- Check the [Setup Guide](./setup.md) for installation issues
|
||||
- Review [Architecture](./architecture.md) for system understanding
|
||||
- See [API Documentation](./api.md) for endpoint details
|
||||
197
docs/api.md
Normal file
197
docs/api.md
Normal file
@@ -0,0 +1,197 @@
|
||||
# API Documentation
|
||||
|
||||
## Overview
|
||||
The Downlink API provides endpoints for fetching YouTube video information and downloading videos/audio in various formats.
|
||||
|
||||
## Base URL
|
||||
- Development: `http://localhost:3000`
|
||||
- Production: `https://your-domain.com`
|
||||
|
||||
## Endpoints
|
||||
|
||||
### Get Video Information
|
||||
|
||||
Retrieve metadata about a YouTube video without downloading it.
|
||||
|
||||
**Endpoint**: `POST /api/info`
|
||||
|
||||
**Request Body**:
|
||||
```json
|
||||
{
|
||||
"url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
|
||||
}
|
||||
```
|
||||
|
||||
**Response** (Success):
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"videoInfo": {
|
||||
"title": "Video Title",
|
||||
"duration": 120,
|
||||
"thumbnail": "https://i.ytimg.com/vi/.../maxresdefault.jpg",
|
||||
"formats": [
|
||||
{
|
||||
"formatId": "137",
|
||||
"ext": "mp4",
|
||||
"resolution": "1920x1080",
|
||||
"filesize": 50000000,
|
||||
"formatNote": "1080p"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Response** (Error):
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"error": "Invalid YouTube URL"
|
||||
}
|
||||
```
|
||||
|
||||
**Status Codes**:
|
||||
- `200`: Success
|
||||
- `400`: Bad Request (invalid URL or missing fields)
|
||||
- `500`: Internal Server Error
|
||||
|
||||
---
|
||||
|
||||
### Download Video/Audio
|
||||
|
||||
Download a YouTube video or extract audio in the specified format.
|
||||
|
||||
**Endpoint**: `POST /api/download`
|
||||
|
||||
**Request Body**:
|
||||
```json
|
||||
{
|
||||
"url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
|
||||
"format": "mp4",
|
||||
"formatType": "video"
|
||||
}
|
||||
```
|
||||
|
||||
**Format Types**:
|
||||
- `"video"`: Download as video file
|
||||
- `"audio"`: Extract audio only
|
||||
|
||||
**Video Formats**:
|
||||
- `"mp4"`: MP4 video (most compatible)
|
||||
- `"webm"`: WebM video (web-optimized)
|
||||
- `"mkv"`: MKV container (high quality)
|
||||
- `"avi"`: AVI video (legacy)
|
||||
|
||||
**Audio Formats**:
|
||||
- `"mp3"`: MP3 audio (most compatible)
|
||||
- `"wav"`: WAV audio (uncompressed)
|
||||
- `"m4a"`: M4A audio (Apple format)
|
||||
- `"opus"`: Opus audio (modern, efficient)
|
||||
|
||||
**Response** (Success):
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"downloadUrl": "/downloads/1234567890-abc123.mp4",
|
||||
"filename": "Video_Title.mp4",
|
||||
"videoInfo": {
|
||||
"title": "Video Title",
|
||||
"duration": 120,
|
||||
"thumbnail": "https://...",
|
||||
"formats": [...]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Response** (Error):
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"error": "Failed to download video"
|
||||
}
|
||||
```
|
||||
|
||||
**Status Codes**:
|
||||
- `200`: Success
|
||||
- `400`: Bad Request (invalid URL, format, or missing fields)
|
||||
- `500`: Internal Server Error
|
||||
|
||||
## Error Handling
|
||||
|
||||
All endpoints return JSON responses with a `success` boolean field. When `success` is `false`, an `error` field contains the error message.
|
||||
|
||||
Common error messages:
|
||||
- `"Missing required fields"`: Required request body fields are missing
|
||||
- `"Invalid YouTube URL"`: The provided URL is not a valid YouTube URL
|
||||
- `"Failed to get video info"`: Error occurred while fetching video metadata
|
||||
- `"Failed to download video"`: Error occurred during download/transcoding
|
||||
|
||||
## Rate Limiting
|
||||
|
||||
Currently, no rate limiting is implemented. Consider adding rate limiting for production use.
|
||||
|
||||
## File Storage
|
||||
|
||||
Downloaded files are stored in `/public/downloads/` and are accessible via the `downloadUrl` returned in the response. Files are named with a timestamp and random ID to avoid conflicts.
|
||||
|
||||
**Note**: Files are not automatically cleaned up. Consider implementing a cleanup job for production.
|
||||
|
||||
## Examples
|
||||
|
||||
### JavaScript/TypeScript
|
||||
|
||||
```typescript
|
||||
// Get video info
|
||||
const infoResponse = await fetch('/api/info', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
url: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ'
|
||||
})
|
||||
});
|
||||
const infoData = await infoResponse.json();
|
||||
|
||||
// Download MP4 video
|
||||
const downloadResponse = await fetch('/api/download', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
url: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ',
|
||||
format: 'mp4',
|
||||
formatType: 'video'
|
||||
})
|
||||
});
|
||||
const downloadData = await downloadResponse.json();
|
||||
|
||||
if (downloadData.success) {
|
||||
// Download the file
|
||||
window.location.href = downloadData.downloadUrl;
|
||||
}
|
||||
```
|
||||
|
||||
### cURL
|
||||
|
||||
```bash
|
||||
# Get video info
|
||||
curl -X POST http://localhost:3000/api/info \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"url":"https://www.youtube.com/watch?v=dQw4w9WgXcQ"}'
|
||||
|
||||
# Download MP3 audio
|
||||
curl -X POST http://localhost:3000/api/download \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"url":"https://www.youtube.com/watch?v=dQw4w9WgXcQ",
|
||||
"format":"mp3",
|
||||
"formatType":"audio"
|
||||
}'
|
||||
```
|
||||
|
||||
## Security Considerations
|
||||
|
||||
- URLs are validated to ensure they are YouTube URLs
|
||||
- Filenames are sanitized to prevent directory traversal
|
||||
- No user authentication is currently implemented
|
||||
- Consider adding file size limits and download quotas
|
||||
- Implement CORS policies if needed for cross-origin requests
|
||||
223
docs/architecture.md
Normal file
223
docs/architecture.md
Normal file
@@ -0,0 +1,223 @@
|
||||
# Architecture Documentation
|
||||
|
||||
## Overview
|
||||
Downlink is a Next.js application that provides a web interface for downloading YouTube videos and audio files. The application uses server-side processing with yt-dlp and provides a modern, responsive UI built with shadcn/ui.
|
||||
|
||||
## System Architecture
|
||||
|
||||
```
|
||||
┌─────────────┐
|
||||
│ Browser │
|
||||
│ (Client) │
|
||||
└──────┬──────┘
|
||||
│ HTTP Requests
|
||||
▼
|
||||
┌─────────────────────────────────┐
|
||||
│ Next.js App Router │
|
||||
│ ┌───────────────────────────┐ │
|
||||
│ │ UI Components (React) │ │
|
||||
│ └───────────────────────────┘ │
|
||||
│ ┌───────────────────────────┐ │
|
||||
│ │ API Routes │ │
|
||||
│ │ - /api/info │ │
|
||||
│ │ - /api/download │ │
|
||||
│ └───────────┬───────────────┘ │
|
||||
└──────────────┼──────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────┐
|
||||
│ Business Logic Layer │
|
||||
│ ┌───────────────────────────┐ │
|
||||
│ │ lib/youtube.ts │ │
|
||||
│ │ - getVideoInfo() │ │
|
||||
│ │ - downloadVideo() │ │
|
||||
│ └───────────┬───────────────┘ │
|
||||
└──────────────┼──────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────┐
|
||||
│ External Tools │
|
||||
│ ┌───────────────────────────┐ │
|
||||
│ │ yt-dlp (Python) │ │
|
||||
│ │ - Video download │ │
|
||||
│ │ - Format conversion │ │
|
||||
│ └───────────────────────────┘ │
|
||||
│ ┌───────────────────────────┐ │
|
||||
│ │ ffmpeg (via yt-dlp) │ │
|
||||
│ │ - Audio transcoding │ │
|
||||
│ └───────────────────────────┘ │
|
||||
└─────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Component Structure
|
||||
|
||||
### Frontend Components
|
||||
|
||||
#### `app/page.tsx`
|
||||
Main page component containing:
|
||||
- URL input field
|
||||
- Video information display
|
||||
- Format selection (video/audio)
|
||||
- Download button
|
||||
- Error handling and success states
|
||||
|
||||
#### UI Components (`components/ui/`)
|
||||
shadcn/ui components:
|
||||
- `button.tsx`: Button component
|
||||
- `input.tsx`: Input field component
|
||||
- `card.tsx`: Card container component
|
||||
- `label.tsx`: Form label component
|
||||
- `select.tsx`: Dropdown select component
|
||||
|
||||
### Backend Components
|
||||
|
||||
#### API Routes
|
||||
|
||||
**`app/api/info/route.ts`**
|
||||
- Handles POST requests for video information
|
||||
- Validates YouTube URL
|
||||
- Calls `getVideoInfo()` from `lib/youtube.ts`
|
||||
- Returns video metadata
|
||||
|
||||
**`app/api/download/route.ts`**
|
||||
- Handles POST requests for downloads
|
||||
- Validates request body (url, format, formatType)
|
||||
- Calls `downloadVideo()` from `lib/youtube.ts`
|
||||
- Returns download URL and file information
|
||||
|
||||
#### Business Logic
|
||||
|
||||
**`lib/youtube.ts`**
|
||||
Core functionality:
|
||||
- `getVideoInfo(url)`: Fetches video metadata using yt-dlp
|
||||
- `downloadVideo(request)`: Downloads and processes video/audio
|
||||
- `ensureDirectories()`: Creates necessary directories
|
||||
- `sanitizeFilename()`: Sanitizes filenames for safe storage
|
||||
|
||||
**`lib/types.ts`**
|
||||
Centralized TypeScript type definitions:
|
||||
- `VideoFormat`, `AudioFormat`: Format type unions
|
||||
- `DownloadRequest`, `DownloadResponse`: API request/response types
|
||||
- `VideoInfo`, `FormatOption`: Video metadata types
|
||||
|
||||
**`lib/utils.ts`**
|
||||
Utility functions:
|
||||
- `cn()`: Tailwind class name merger
|
||||
- `isValidYouTubeUrl()`: URL validation
|
||||
- `extractYouTubeId()`: Extract video ID from URL
|
||||
|
||||
## Data Flow
|
||||
|
||||
### Video Information Flow
|
||||
1. User enters YouTube URL and clicks "Get Info"
|
||||
2. Frontend sends POST request to `/api/info`
|
||||
3. API route validates URL and calls `getVideoInfo()`
|
||||
4. `getVideoInfo()` executes `yt-dlp --dump-json`
|
||||
5. JSON response is parsed and formatted
|
||||
6. Video info (title, thumbnail, duration) returned to frontend
|
||||
7. Frontend displays video information
|
||||
|
||||
### Download Flow
|
||||
1. User selects format and clicks "Download"
|
||||
2. Frontend sends POST request to `/api/download`
|
||||
3. API route validates request and calls `downloadVideo()`
|
||||
4. `downloadVideo()`:
|
||||
- Generates unique file ID
|
||||
- Constructs yt-dlp command based on format
|
||||
- Executes download command
|
||||
- Moves file to `/public/downloads/`
|
||||
- Returns download URL
|
||||
5. Frontend receives download URL
|
||||
6. User can download file via provided link
|
||||
|
||||
## File Storage
|
||||
|
||||
### Directory Structure
|
||||
```
|
||||
Downlink/
|
||||
├── downloads/ # Temporary storage (gitignored)
|
||||
│ └── [fileId].[ext] # Downloaded files before processing
|
||||
├── public/
|
||||
│ └── downloads/ # Public downloads (gitignored)
|
||||
│ └── [fileId].[ext] # Final files served to users
|
||||
```
|
||||
|
||||
### File Naming
|
||||
- Format: `[timestamp]-[randomId].[extension]`
|
||||
- Example: `1234567890-abc123.mp4`
|
||||
- Prevents filename conflicts
|
||||
- Timestamp enables cleanup of old files
|
||||
|
||||
## Dependencies
|
||||
|
||||
### Runtime Dependencies
|
||||
- **next**: Next.js framework
|
||||
- **react**: React library
|
||||
- **react-dom**: React DOM rendering
|
||||
- **lucide-react**: Icon library
|
||||
- **@radix-ui/***: UI component primitives
|
||||
- **tailwind-merge**: Tailwind class merging
|
||||
- **clsx**: Conditional class names
|
||||
|
||||
### System Dependencies
|
||||
- **yt-dlp**: Python-based YouTube downloader
|
||||
- **ffmpeg**: Media conversion tool (used by yt-dlp)
|
||||
|
||||
### Development Dependencies
|
||||
- **typescript**: TypeScript compiler
|
||||
- **tailwindcss**: CSS framework
|
||||
- **eslint**: Code linting
|
||||
|
||||
## Security Considerations
|
||||
|
||||
### Current Implementation
|
||||
- URL validation to ensure YouTube URLs only
|
||||
- Filename sanitization to prevent directory traversal
|
||||
- Server-side processing (no client-side download logic)
|
||||
|
||||
### Recommended Enhancements
|
||||
- Rate limiting to prevent abuse
|
||||
- File size limits
|
||||
- User authentication/authorization
|
||||
- Download quotas per user/IP
|
||||
- Automatic file cleanup
|
||||
- CORS configuration
|
||||
- Input sanitization for all user inputs
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
### Current Limitations
|
||||
- Synchronous file operations (could block for large files)
|
||||
- No progress tracking during downloads
|
||||
- Files stored in memory during copy operations
|
||||
- No caching of video information
|
||||
|
||||
### Optimization Opportunities
|
||||
- Stream large files instead of loading into memory
|
||||
- Implement download progress tracking
|
||||
- Cache video metadata
|
||||
- Use background jobs for long-running downloads
|
||||
- Implement CDN for file serving
|
||||
- Add database for download history
|
||||
|
||||
## Deployment Considerations
|
||||
|
||||
### Requirements
|
||||
- Node.js 18+ runtime
|
||||
- Python 3.6+ (for yt-dlp)
|
||||
- ffmpeg installed on server
|
||||
- Sufficient disk space for downloads
|
||||
- Network access to YouTube
|
||||
|
||||
### Environment Variables
|
||||
Currently none required, but consider:
|
||||
- `MAX_FILE_SIZE`: Maximum file size limit
|
||||
- `CLEANUP_INTERVAL`: File cleanup schedule
|
||||
- `ALLOWED_DOMAINS`: Allowed video platforms
|
||||
- `STORAGE_PATH`: Custom storage location
|
||||
|
||||
### Scaling Considerations
|
||||
- Stateless API design (can scale horizontally)
|
||||
- File storage should be shared (S3, etc.) for multi-instance deployments
|
||||
- Consider message queue for download processing
|
||||
- Implement caching layer for video metadata
|
||||
158
docs/configuration.md
Normal file
158
docs/configuration.md
Normal file
@@ -0,0 +1,158 @@
|
||||
# Configuration Guide
|
||||
|
||||
## Environment Variables
|
||||
|
||||
Downlink uses environment variables for configuration. Create a `.env.local` file in the project root (this file is gitignored and won't be committed).
|
||||
|
||||
### Required Configuration
|
||||
|
||||
#### YT_DLP_PATH
|
||||
**Required if yt-dlp is not in your system PATH**
|
||||
|
||||
Full path to the yt-dlp executable.
|
||||
|
||||
```bash
|
||||
YT_DLP_PATH=/Users/jeff/Desktop/yt-dlp_macos
|
||||
```
|
||||
|
||||
**When to set this:**
|
||||
- yt-dlp is not installed via package manager (brew, pip, etc.)
|
||||
- yt-dlp is in a custom location
|
||||
- You're using a standalone yt-dlp binary
|
||||
|
||||
**How to find your yt-dlp path:**
|
||||
```bash
|
||||
# If installed via brew
|
||||
which yt-dlp
|
||||
# Output: /opt/homebrew/bin/yt-dlp
|
||||
|
||||
# If installed via pip
|
||||
which yt-dlp
|
||||
# Output: /usr/local/bin/yt-dlp
|
||||
|
||||
# If using standalone binary
|
||||
# Use the full path to the binary file
|
||||
```
|
||||
|
||||
### Optional Configuration
|
||||
|
||||
#### FFMPEG_PATH
|
||||
**Optional - Reserved for future use**
|
||||
|
||||
Full path to ffmpeg executable (currently not used, but reserved for future configuration).
|
||||
|
||||
```bash
|
||||
FFMPEG_PATH=/usr/local/bin/ffmpeg
|
||||
```
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
### Example 1: yt-dlp in Custom Location
|
||||
```bash
|
||||
# .env.local
|
||||
YT_DLP_PATH=/Users/jeff/Desktop/yt-dlp_macos
|
||||
```
|
||||
|
||||
### Example 2: yt-dlp Installed via Homebrew
|
||||
```bash
|
||||
# .env.local
|
||||
# Can be left empty if yt-dlp is in PATH
|
||||
# Or explicitly set:
|
||||
YT_DLP_PATH=/opt/homebrew/bin/yt-dlp
|
||||
```
|
||||
|
||||
### Example 3: yt-dlp Installed via pip
|
||||
```bash
|
||||
# .env.local
|
||||
YT_DLP_PATH=/usr/local/bin/yt-dlp
|
||||
```
|
||||
|
||||
## Environment File Setup
|
||||
|
||||
1. **Copy the example file:**
|
||||
```bash
|
||||
cp .env.example .env.local
|
||||
```
|
||||
|
||||
2. **Edit `.env.local` with your configuration:**
|
||||
```bash
|
||||
YT_DLP_PATH=/path/to/your/yt-dlp
|
||||
```
|
||||
|
||||
3. **Restart the development server:**
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### yt-dlp not found error
|
||||
If you see `yt-dlp: command not found`:
|
||||
|
||||
1. **Check if yt-dlp exists:**
|
||||
```bash
|
||||
which yt-dlp
|
||||
```
|
||||
|
||||
2. **If it returns nothing, set YT_DLP_PATH:**
|
||||
```bash
|
||||
# Find where yt-dlp is located
|
||||
find /usr -name yt-dlp 2>/dev/null
|
||||
find ~ -name yt-dlp 2>/dev/null
|
||||
|
||||
# Or if you downloaded it manually, use that path
|
||||
```
|
||||
|
||||
3. **Add to .env.local:**
|
||||
```bash
|
||||
YT_DLP_PATH=/full/path/to/yt-dlp
|
||||
```
|
||||
|
||||
4. **Verify the path is correct:**
|
||||
```bash
|
||||
ls -la "$YT_DLP_PATH"
|
||||
# Should show the yt-dlp executable
|
||||
```
|
||||
|
||||
### Path with spaces
|
||||
If your path contains spaces, use quotes in the environment variable:
|
||||
```bash
|
||||
YT_DLP_PATH="/Users/jeff/My Apps/yt-dlp_macos"
|
||||
```
|
||||
|
||||
### Executable permissions
|
||||
Ensure yt-dlp has execute permissions:
|
||||
```bash
|
||||
chmod +x /path/to/yt-dlp
|
||||
```
|
||||
|
||||
## Production Configuration
|
||||
|
||||
For production deployments:
|
||||
|
||||
1. Set environment variables in your hosting platform (Vercel, Railway, etc.)
|
||||
2. Ensure yt-dlp is installed on the server
|
||||
3. Set `YT_DLP_PATH` if yt-dlp is not in the default PATH
|
||||
|
||||
### Vercel Example
|
||||
```bash
|
||||
# In Vercel dashboard → Settings → Environment Variables
|
||||
YT_DLP_PATH=/usr/local/bin/yt-dlp
|
||||
```
|
||||
|
||||
### Docker Example
|
||||
```dockerfile
|
||||
# In Dockerfile
|
||||
ENV YT_DLP_PATH=/usr/local/bin/yt-dlp
|
||||
```
|
||||
|
||||
## Next.js Environment Variables
|
||||
|
||||
Next.js automatically loads `.env.local` files. Variables prefixed with `NEXT_PUBLIC_` are exposed to the browser, but `YT_DLP_PATH` should remain server-side only (no prefix).
|
||||
|
||||
## Security Notes
|
||||
|
||||
- Never commit `.env.local` to version control (already in .gitignore)
|
||||
- Keep yt-dlp paths secure
|
||||
- Use absolute paths for reliability
|
||||
- Test configuration after changes
|
||||
174
docs/features.md
Normal file
174
docs/features.md
Normal file
@@ -0,0 +1,174 @@
|
||||
# Features Documentation
|
||||
|
||||
## Current Features
|
||||
|
||||
### 1. YouTube Video Information Retrieval
|
||||
- Fetch video metadata without downloading
|
||||
- Display video title, thumbnail, and duration
|
||||
- View available formats
|
||||
|
||||
**Implementation**: `app/api/info` endpoint
|
||||
|
||||
### 2. Video Download
|
||||
- Download videos in multiple formats:
|
||||
- MP4 (most compatible)
|
||||
- WebM (web-optimized)
|
||||
- MKV (high quality)
|
||||
- AVI (legacy support)
|
||||
|
||||
**Implementation**: `app/api/download` endpoint with `formatType: "video"`
|
||||
|
||||
### 3. Audio Extraction
|
||||
- Extract audio from videos in multiple formats:
|
||||
- MP3 (most compatible, compressed)
|
||||
- WAV (uncompressed, high quality)
|
||||
- M4A (Apple format)
|
||||
- Opus (modern, efficient)
|
||||
|
||||
**Implementation**: `app/api/download` endpoint with `formatType: "audio"`
|
||||
|
||||
### 4. Format Transcoding
|
||||
- Automatic format conversion using yt-dlp and ffmpeg
|
||||
- Best quality selection for requested format
|
||||
- Audio extraction and conversion for audio formats
|
||||
|
||||
**Implementation**: Server-side processing in `lib/youtube.ts`
|
||||
|
||||
### 5. Modern UI
|
||||
- Responsive design with Tailwind CSS
|
||||
- shadcn/ui components for consistent styling
|
||||
- Loading states and error handling
|
||||
- Video thumbnail preview
|
||||
- Format selection dropdowns
|
||||
|
||||
**Implementation**: `app/page.tsx` with shadcn/ui components
|
||||
|
||||
### 6. URL Validation
|
||||
- Client-side and server-side URL validation
|
||||
- Support for various YouTube URL formats:
|
||||
- `https://www.youtube.com/watch?v=...`
|
||||
- `https://youtu.be/...`
|
||||
- `youtube.com/watch?v=...`
|
||||
|
||||
**Implementation**: `lib/utils.ts` - `isValidYouTubeUrl()`
|
||||
|
||||
### 7. Safe File Handling
|
||||
- Filename sanitization to prevent directory traversal
|
||||
- Unique file IDs to prevent conflicts
|
||||
- Proper file extension handling
|
||||
|
||||
**Implementation**: `lib/youtube.ts` - `sanitizeFilename()`
|
||||
|
||||
## Feature Roadmap
|
||||
|
||||
### Planned Features
|
||||
|
||||
#### Short Term
|
||||
- [ ] Download progress tracking
|
||||
- [ ] File size display before download
|
||||
- [ ] Video quality selection (720p, 1080p, etc.)
|
||||
- [ ] Download history
|
||||
- [ ] Error recovery and retry mechanism
|
||||
|
||||
#### Medium Term
|
||||
- [ ] Playlist support
|
||||
- [ ] Batch downloads
|
||||
- [ ] Custom ffmpeg parameters
|
||||
- [ ] Download queue management
|
||||
- [ ] File cleanup automation
|
||||
|
||||
#### Long Term
|
||||
- [ ] User authentication
|
||||
- [ ] Download quotas and limits
|
||||
- [ ] Cloud storage integration (S3, etc.)
|
||||
- [ ] API rate limiting
|
||||
- [ ] Webhook notifications
|
||||
- [ ] Mobile app support
|
||||
|
||||
## Feature Usage Examples
|
||||
|
||||
### Download MP4 Video
|
||||
```typescript
|
||||
const response = await fetch('/api/download', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
url: 'https://www.youtube.com/watch?v=...',
|
||||
format: 'mp4',
|
||||
formatType: 'video'
|
||||
})
|
||||
});
|
||||
```
|
||||
|
||||
### Extract MP3 Audio
|
||||
```typescript
|
||||
const response = await fetch('/api/download', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
url: 'https://www.youtube.com/watch?v=...',
|
||||
format: 'mp3',
|
||||
formatType: 'audio'
|
||||
})
|
||||
});
|
||||
```
|
||||
|
||||
### Get Video Info
|
||||
```typescript
|
||||
const response = await fetch('/api/info', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
url: 'https://www.youtube.com/watch?v=...'
|
||||
})
|
||||
});
|
||||
```
|
||||
|
||||
## Feature Limitations
|
||||
|
||||
### Current Limitations
|
||||
1. **No Progress Tracking**: Users cannot see download progress
|
||||
2. **No File Size Limits**: Large files may cause issues
|
||||
3. **No Cleanup**: Files accumulate in storage
|
||||
4. **Single Format**: One format per download request
|
||||
5. **No Playlist Support**: Only single videos
|
||||
6. **No Quality Selection**: Downloads best available quality
|
||||
7. **No Authentication**: No user accounts or history
|
||||
|
||||
### Known Issues
|
||||
- Large files may timeout on slow connections
|
||||
- Some videos may not be available in requested format
|
||||
- Audio conversion (MP3/WAV) requires ffmpeg
|
||||
- No validation of available formats before download
|
||||
|
||||
## Feature Dependencies
|
||||
|
||||
### Required System Tools
|
||||
- **yt-dlp**: For video downloading and format selection
|
||||
- **ffmpeg**: For audio format conversion (MP3, WAV)
|
||||
|
||||
### Required npm Packages
|
||||
- Next.js 16+
|
||||
- React 19+
|
||||
- shadcn/ui components
|
||||
- Tailwind CSS
|
||||
- Lucide React (icons)
|
||||
|
||||
## Feature Testing
|
||||
|
||||
### Manual Testing Checklist
|
||||
- [ ] Enter valid YouTube URL and get info
|
||||
- [ ] Download video in MP4 format
|
||||
- [ ] Download video in WebM format
|
||||
- [ ] Extract audio as MP3
|
||||
- [ ] Extract audio as WAV
|
||||
- [ ] Test with invalid URL (should show error)
|
||||
- [ ] Test with missing format (should show error)
|
||||
- [ ] Verify file downloads correctly
|
||||
- [ ] Check filename sanitization
|
||||
|
||||
### Automated Testing (Future)
|
||||
- Unit tests for utility functions
|
||||
- Integration tests for API endpoints
|
||||
- E2E tests for user flows
|
||||
- Format validation tests
|
||||
153
docs/setup.md
Normal file
153
docs/setup.md
Normal file
@@ -0,0 +1,153 @@
|
||||
# Setup Guide
|
||||
|
||||
## Prerequisites
|
||||
|
||||
### System Requirements
|
||||
- Node.js 18+ and npm
|
||||
- Python 3.6+ (for yt-dlp)
|
||||
- ffmpeg (for audio conversion)
|
||||
|
||||
### Installing Dependencies
|
||||
|
||||
#### macOS
|
||||
```bash
|
||||
# Install yt-dlp
|
||||
brew install yt-dlp
|
||||
|
||||
# Install ffmpeg
|
||||
brew install ffmpeg
|
||||
```
|
||||
|
||||
#### Linux (Ubuntu/Debian)
|
||||
```bash
|
||||
# Install yt-dlp
|
||||
pip3 install yt-dlp
|
||||
|
||||
# Install ffmpeg
|
||||
sudo apt-get update
|
||||
sudo apt-get install ffmpeg
|
||||
```
|
||||
|
||||
#### Windows
|
||||
```bash
|
||||
# Install yt-dlp
|
||||
pip install yt-dlp
|
||||
|
||||
# Install ffmpeg
|
||||
# Download from https://ffmpeg.org/download.html
|
||||
# Add to PATH
|
||||
```
|
||||
|
||||
## Installation
|
||||
|
||||
1. **Clone the repository**
|
||||
```bash
|
||||
git clone <repository-url>
|
||||
cd Downlink
|
||||
```
|
||||
|
||||
2. **Install npm dependencies**
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
3. **Verify yt-dlp installation**
|
||||
```bash
|
||||
yt-dlp --version
|
||||
```
|
||||
|
||||
4. **Verify ffmpeg installation**
|
||||
```bash
|
||||
ffmpeg -version
|
||||
```
|
||||
|
||||
## Running the Application
|
||||
|
||||
### Development Mode
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
The application will be available at `http://localhost:3000`
|
||||
|
||||
### Production Build
|
||||
```bash
|
||||
npm run build
|
||||
npm start
|
||||
```
|
||||
|
||||
## Directory Structure
|
||||
|
||||
```
|
||||
Downlink/
|
||||
├── app/ # Next.js app directory
|
||||
│ ├── api/ # API routes
|
||||
│ │ ├── download/ # Download endpoint
|
||||
│ │ └── info/ # Video info endpoint
|
||||
│ ├── page.tsx # Main page
|
||||
│ └── layout.tsx # Root layout
|
||||
├── components/ # React components
|
||||
│ └── ui/ # shadcn/ui components
|
||||
├── lib/ # Utility functions
|
||||
│ ├── types.ts # TypeScript types
|
||||
│ └── youtube.ts # YouTube download logic
|
||||
├── docs/ # Documentation
|
||||
├── downloads/ # Temporary download storage (gitignored)
|
||||
└── public/
|
||||
└── downloads/ # Served download files (gitignored)
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
|
||||
Create a `.env.local` file in the project root (copy from `.env.example`):
|
||||
|
||||
```bash
|
||||
# Required if yt-dlp is not in PATH
|
||||
YT_DLP_PATH=/path/to/yt-dlp
|
||||
|
||||
# Optional: FFmpeg path (if not in PATH)
|
||||
# FFMPEG_PATH=/path/to/ffmpeg
|
||||
```
|
||||
|
||||
### Available Variables
|
||||
|
||||
- **`YT_DLP_PATH`** (optional): Full path to yt-dlp executable if not in PATH
|
||||
- Example: `YT_DLP_PATH=/Users/jeff/Desktop/yt-dlp_macos`
|
||||
- Example: `YT_DLP_PATH=/opt/homebrew/bin/yt-dlp`
|
||||
- If not set, the system will look for `yt-dlp` in PATH
|
||||
|
||||
- **`FFMPEG_PATH`** (optional): Full path to ffmpeg executable if not in PATH
|
||||
- Currently not used but reserved for future use
|
||||
|
||||
### Future Environment Variables
|
||||
- `MAX_FILE_SIZE`: Maximum file size limit
|
||||
- `CLEANUP_INTERVAL`: File cleanup interval
|
||||
- `ALLOWED_DOMAINS`: Allowed video domains
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### yt-dlp not found
|
||||
- Ensure yt-dlp is installed and in your PATH
|
||||
- Try: `which yt-dlp` to verify installation
|
||||
- Reinstall if needed: `pip3 install --upgrade yt-dlp`
|
||||
|
||||
### ffmpeg not found
|
||||
- Ensure ffmpeg is installed and in your PATH
|
||||
- Try: `which ffmpeg` to verify installation
|
||||
- Audio conversion (MP3, WAV) will fail without ffmpeg
|
||||
|
||||
### Download fails
|
||||
- Check YouTube URL format
|
||||
- Verify internet connection
|
||||
- Check server logs for detailed error messages
|
||||
- Ensure sufficient disk space in downloads directory
|
||||
|
||||
### Port already in use
|
||||
- Change port: `npm run dev -- -p 3001`
|
||||
- Or kill process using port 3000
|
||||
|
||||
## Next Steps
|
||||
|
||||
- Read [YouTube Downloader Documentation](./youtube-downloader.md)
|
||||
- Read [Transcoding Documentation](./transcoding.md)
|
||||
- Check [Agent Instructions](./AGENTS.md) for contributing guidelines
|
||||
114
docs/transcoding.md
Normal file
114
docs/transcoding.md
Normal file
@@ -0,0 +1,114 @@
|
||||
# Transcoding Feature
|
||||
|
||||
## Overview
|
||||
The transcoding feature converts downloaded YouTube videos and audio files into different formats. This allows users to download content in their preferred format (MP4, WebM, MP3, WAV, etc.) regardless of the original format.
|
||||
|
||||
## Usage
|
||||
|
||||
### Format Selection
|
||||
Users can select from the following formats:
|
||||
|
||||
**Video Formats**:
|
||||
- MP4 (most compatible)
|
||||
- WebM (web-optimized)
|
||||
- MKV (high quality)
|
||||
- AVI (legacy support)
|
||||
|
||||
**Audio Formats**:
|
||||
- MP3 (most compatible, compressed)
|
||||
- WAV (uncompressed, high quality)
|
||||
- M4A (Apple format, good quality)
|
||||
- Opus (modern, efficient)
|
||||
|
||||
### How It Works
|
||||
1. User selects desired format from dropdown
|
||||
2. System downloads best available format from YouTube
|
||||
3. For audio formats (MP3, WAV), yt-dlp extracts audio and converts
|
||||
4. For video formats, yt-dlp selects best matching format or transcodes if needed
|
||||
5. Converted file is saved and served to user
|
||||
|
||||
## Technical Details
|
||||
|
||||
### Implementation
|
||||
|
||||
#### Audio Transcoding
|
||||
Audio formats like MP3 and WAV require extraction and conversion:
|
||||
- yt-dlp downloads best audio stream (usually M4A)
|
||||
- Uses ffmpeg (via yt-dlp) to convert to requested format
|
||||
- Command: `yt-dlp -f "bestaudio" -x --audio-format mp3 --audio-quality 0`
|
||||
|
||||
#### Video Transcoding
|
||||
Video formats use format selection:
|
||||
- yt-dlp attempts to find matching format
|
||||
- Falls back to best available format if exact match not found
|
||||
- May combine video and audio streams if needed
|
||||
|
||||
### Code Location
|
||||
- Format handling: `lib/youtube.ts` - `downloadVideo()` function
|
||||
- Format selection logic determines yt-dlp command based on requested format
|
||||
|
||||
### Format Mapping
|
||||
|
||||
```typescript
|
||||
// Video formats
|
||||
mp4 → bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best
|
||||
webm → bestvideo[ext=webm]+bestaudio[ext=m4a]/best[ext=webm]/best
|
||||
mkv → bestvideo[ext=mkv]+bestaudio[ext=m4a]/best[ext=mkv]/best
|
||||
avi → bestvideo[ext=avi]+bestaudio[ext=m4a]/best[ext=avi]/best
|
||||
|
||||
// Audio formats
|
||||
mp3 → bestaudio[ext=m4a]/bestaudio + convert to MP3
|
||||
wav → bestaudio[ext=m4a]/bestaudio + convert to WAV
|
||||
m4a → bestaudio[ext=m4a]/bestaudio
|
||||
opus → bestaudio[ext=opus]/bestaudio
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### Audio Quality
|
||||
Currently set to highest quality (`--audio-quality 0`). Can be adjusted:
|
||||
- `0`: Best quality (largest file)
|
||||
- `5`: Default quality
|
||||
- `9`: Lower quality (smaller file)
|
||||
|
||||
### Video Quality
|
||||
Currently downloads best available. Could be enhanced to allow:
|
||||
- Resolution selection (720p, 1080p, etc.)
|
||||
- Bitrate selection
|
||||
- Codec preference
|
||||
|
||||
## Examples
|
||||
|
||||
### Transcoding Flow
|
||||
```typescript
|
||||
// User requests MP3
|
||||
{
|
||||
url: "https://youtube.com/watch?v=...",
|
||||
format: "mp3",
|
||||
formatType: "audio"
|
||||
}
|
||||
|
||||
// System process:
|
||||
// 1. Download best audio (M4A)
|
||||
// 2. Extract audio stream
|
||||
// 3. Convert to MP3 using ffmpeg
|
||||
// 4. Save as .mp3 file
|
||||
```
|
||||
|
||||
## Dependencies
|
||||
- **yt-dlp**: Handles format selection and basic conversion
|
||||
- **ffmpeg**: Required for audio format conversion (MP3, WAV)
|
||||
|
||||
## Limitations
|
||||
- Transcoding happens server-side and can be CPU-intensive
|
||||
- Large files may take significant time to process
|
||||
- No progress indication during transcoding
|
||||
- Quality settings are fixed (best quality)
|
||||
|
||||
## Future Improvements
|
||||
- Add quality/bitrate selection options
|
||||
- Add resolution selection for video
|
||||
- Add progress tracking for transcoding
|
||||
- Add batch transcoding support
|
||||
- Add preview/thumbnail generation
|
||||
- Add custom ffmpeg parameters option
|
||||
190
docs/troubleshooting.md
Normal file
190
docs/troubleshooting.md
Normal file
@@ -0,0 +1,190 @@
|
||||
# Troubleshooting Guide
|
||||
|
||||
## Common Issues and Solutions
|
||||
|
||||
### Error: stdout maxBuffer length exceeded
|
||||
|
||||
**Symptoms:**
|
||||
- API returns 500 error
|
||||
- Error message: `RangeError: stdout maxBuffer length exceeded`
|
||||
- Happens with long videos or videos with many format options
|
||||
|
||||
**Cause:**
|
||||
Node.js's `exec` function has a default `maxBuffer` of 1MB. For long videos, yt-dlp returns very large JSON output (especially with storyboard fragments) that exceeds this limit.
|
||||
|
||||
**Solution:**
|
||||
The code now uses a 10MB buffer. If you encounter this error again, you can increase it further in `lib/youtube.ts`:
|
||||
|
||||
```typescript
|
||||
await execAsync(command, { maxBuffer: 20 * 1024 * 1024 }); // 20MB buffer
|
||||
```
|
||||
|
||||
**Status:** ✅ Fixed in current version
|
||||
|
||||
---
|
||||
|
||||
### Error: yt-dlp command not found
|
||||
|
||||
**Symptoms:**
|
||||
- Error: `yt-dlp: command not found`
|
||||
- API returns 500 error
|
||||
|
||||
**Cause:**
|
||||
yt-dlp is not in your system PATH or the path in `.env.local` is incorrect.
|
||||
|
||||
**Solution:**
|
||||
1. Check if yt-dlp exists:
|
||||
```bash
|
||||
which yt-dlp
|
||||
```
|
||||
|
||||
2. If not found, set `YT_DLP_PATH` in `.env.local`:
|
||||
```bash
|
||||
YT_DLP_PATH=/full/path/to/yt-dlp
|
||||
```
|
||||
|
||||
3. Restart the dev server
|
||||
|
||||
**Status:** ✅ Fixed with environment variable configuration
|
||||
|
||||
---
|
||||
|
||||
### Error: Failed to get video info
|
||||
|
||||
**Symptoms:**
|
||||
- API returns 500 error
|
||||
- Generic error message: "Failed to get video info"
|
||||
|
||||
**Possible Causes:**
|
||||
1. **Invalid YouTube URL** - Check URL format
|
||||
2. **Video is private/restricted** - Video may not be accessible
|
||||
3. **Network issues** - Check internet connection
|
||||
4. **yt-dlp needs update** - Update yt-dlp: `pip install --upgrade yt-dlp`
|
||||
|
||||
**Solution:**
|
||||
Check server logs for detailed error messages. The logs will show the actual yt-dlp error.
|
||||
|
||||
---
|
||||
|
||||
### Warning: No supported JavaScript runtime
|
||||
|
||||
**Symptoms:**
|
||||
- Warning in logs: `No supported JavaScript runtime could be found`
|
||||
- Some formats may be missing
|
||||
|
||||
**Cause:**
|
||||
yt-dlp needs a JavaScript runtime for some YouTube features. This is optional but recommended.
|
||||
|
||||
**Solution:**
|
||||
Install a JavaScript runtime (optional):
|
||||
```bash
|
||||
# Install Node.js (if not already installed)
|
||||
brew install node
|
||||
|
||||
# Or install deno
|
||||
brew install deno
|
||||
```
|
||||
|
||||
**Note:** This is a warning, not an error. The app will still work, but some formats may be unavailable.
|
||||
|
||||
---
|
||||
|
||||
### Download fails but info works
|
||||
|
||||
**Symptoms:**
|
||||
- `/api/info` works fine
|
||||
- `/api/download` fails
|
||||
|
||||
**Possible Causes:**
|
||||
1. **Disk space** - Check available disk space
|
||||
2. **Permissions** - Ensure write permissions for `downloads/` and `public/downloads/`
|
||||
3. **ffmpeg missing** - Required for audio conversion (MP3, WAV)
|
||||
|
||||
**Solution:**
|
||||
1. Check disk space: `df -h`
|
||||
2. Check permissions: `ls -la downloads/ public/downloads/`
|
||||
3. Install ffmpeg: `brew install ffmpeg`
|
||||
|
||||
---
|
||||
|
||||
### Files not cleaning up
|
||||
|
||||
**Symptoms:**
|
||||
- Downloaded files accumulate in `public/downloads/`
|
||||
- Disk space fills up
|
||||
|
||||
**Cause:**
|
||||
No automatic cleanup is implemented yet.
|
||||
|
||||
**Solution:**
|
||||
Manually clean up old files:
|
||||
```bash
|
||||
# Remove files older than 24 hours
|
||||
find public/downloads/ -type f -mtime +1 -delete
|
||||
```
|
||||
|
||||
**Future:** Automatic cleanup will be added in a future update.
|
||||
|
||||
---
|
||||
|
||||
### Environment variable not loading
|
||||
|
||||
**Symptoms:**
|
||||
- `.env.local` exists but variables aren't being used
|
||||
- Still using default `yt-dlp` path
|
||||
|
||||
**Solution:**
|
||||
1. Ensure file is named exactly `.env.local` (not `.env.local.txt`)
|
||||
2. Restart the dev server completely (stop and start)
|
||||
3. Check server startup logs for: `Environments: .env.local`
|
||||
4. Verify no syntax errors in `.env.local` (no spaces around `=`)
|
||||
|
||||
---
|
||||
|
||||
## Getting Help
|
||||
|
||||
### Check Server Logs
|
||||
The dev server logs show detailed error information. Look for:
|
||||
- `[getVideoInfo] Using yt-dlp path:` - Confirms path is loaded
|
||||
- `Error getting video info:` - Shows actual error
|
||||
- `POST /api/info 500` - HTTP status codes
|
||||
|
||||
### Enable Debug Logging
|
||||
Debug logging is automatically enabled in development mode. Check console output for:
|
||||
- yt-dlp path being used
|
||||
- Command execution errors
|
||||
- File operation errors
|
||||
|
||||
### Test yt-dlp Directly
|
||||
Test yt-dlp outside the app:
|
||||
```bash
|
||||
yt-dlp --dump-json --no-download "https://www.youtube.com/watch?v=VIDEO_ID"
|
||||
```
|
||||
|
||||
If this fails, the issue is with yt-dlp configuration, not the app.
|
||||
|
||||
---
|
||||
|
||||
## Performance Issues
|
||||
|
||||
### Slow API Responses
|
||||
- Normal: 5-10 seconds for video info
|
||||
- Normal: 30-60+ seconds for downloads (depends on video length)
|
||||
- If slower, check network connection and yt-dlp version
|
||||
|
||||
### High Memory Usage
|
||||
- Large videos with many formats use more memory
|
||||
- Consider increasing Node.js memory limit if needed:
|
||||
```bash
|
||||
NODE_OPTIONS="--max-old-space-size=4096" npm run dev
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Still Having Issues?
|
||||
|
||||
1. Check the [Setup Guide](./setup.md) for installation issues
|
||||
2. Review [Configuration](./configuration.md) for environment variables
|
||||
3. Check server logs for detailed error messages
|
||||
4. Test yt-dlp directly from command line
|
||||
5. Ensure all dependencies are installed and up to date
|
||||
161
docs/youtube-downloader.md
Normal file
161
docs/youtube-downloader.md
Normal file
@@ -0,0 +1,161 @@
|
||||
# YouTube Downloader Feature
|
||||
|
||||
## Overview
|
||||
The YouTube Downloader feature allows users to download YouTube videos and audio files in various formats. Users can paste a YouTube URL, select their preferred format (video or audio), and download the transcoded file.
|
||||
|
||||
## Usage
|
||||
|
||||
### User Flow
|
||||
1. User pastes a YouTube URL into the input field
|
||||
2. User clicks "Get Info" to fetch video metadata (title, thumbnail, duration)
|
||||
3. User selects format type (Video or Audio)
|
||||
4. User selects specific format (MP4, WebM, MKV, AVI for video; MP3, WAV, M4A, Opus for audio)
|
||||
5. User clicks "Download" to start the download process
|
||||
6. Once complete, user receives a download link
|
||||
|
||||
### API Endpoints
|
||||
|
||||
#### GET Video Information
|
||||
**Endpoint**: `POST /api/info`
|
||||
|
||||
**Request Body**:
|
||||
```json
|
||||
{
|
||||
"url": "https://www.youtube.com/watch?v=..."
|
||||
}
|
||||
```
|
||||
|
||||
**Response**:
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"videoInfo": {
|
||||
"title": "Video Title",
|
||||
"duration": 120,
|
||||
"thumbnail": "https://...",
|
||||
"formats": [...]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Download Video/Audio
|
||||
**Endpoint**: `POST /api/download`
|
||||
|
||||
**Request Body**:
|
||||
```json
|
||||
{
|
||||
"url": "https://www.youtube.com/watch?v=...",
|
||||
"format": "mp4",
|
||||
"formatType": "video"
|
||||
}
|
||||
```
|
||||
|
||||
**Response**:
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"downloadUrl": "/downloads/1234567890-abc123.mp4",
|
||||
"filename": "Video Title.mp4",
|
||||
"videoInfo": {...}
|
||||
}
|
||||
```
|
||||
|
||||
## Technical Details
|
||||
|
||||
### Dependencies
|
||||
- **yt-dlp**: Python-based YouTube downloader (must be installed system-wide)
|
||||
- **ffmpeg**: Required for audio format conversion (MP3, WAV)
|
||||
|
||||
### Implementation
|
||||
|
||||
#### Server-Side Processing
|
||||
- Downloads are processed server-side using `yt-dlp`
|
||||
- Files are temporarily stored in `/downloads` directory
|
||||
- Completed files are moved to `/public/downloads` for serving
|
||||
- Files are named with timestamp and random ID to avoid conflicts
|
||||
|
||||
#### Format Handling
|
||||
- **Video formats**: MP4, WebM, MKV, AVI
|
||||
- **Audio formats**: MP3, WAV, M4A, Opus
|
||||
- MP3 and WAV require audio extraction and conversion via yt-dlp
|
||||
- Other formats use direct format selection from available streams
|
||||
|
||||
#### File Storage
|
||||
- Temporary storage: `downloads/` (excluded from git)
|
||||
- Public storage: `public/downloads/` (served statically)
|
||||
- Files are not automatically cleaned up (consider adding cleanup job)
|
||||
|
||||
### Code Structure
|
||||
- **Types**: `lib/types.ts` - Centralized type definitions
|
||||
- **YouTube Logic**: `lib/youtube.ts` - Core download and info functions
|
||||
- **API Routes**:
|
||||
- `app/api/info/route.ts` - Video information endpoint
|
||||
- `app/api/download/route.ts` - Download endpoint
|
||||
- **UI**: `app/page.tsx` - Main user interface
|
||||
|
||||
## Configuration
|
||||
|
||||
### Environment Variables
|
||||
|
||||
Create a `.env.local` file in the project root:
|
||||
|
||||
```bash
|
||||
# Required if yt-dlp is not in PATH
|
||||
YT_DLP_PATH=/path/to/yt-dlp
|
||||
```
|
||||
|
||||
- **`YT_DLP_PATH`**: Full path to yt-dlp executable if not in system PATH
|
||||
- Required if yt-dlp is not installed via package manager
|
||||
- Example: `YT_DLP_PATH=/Users/jeff/Desktop/yt-dlp_macos`
|
||||
|
||||
Future environment variables:
|
||||
- `MAX_FILE_SIZE`: Maximum file size limit
|
||||
- `CLEANUP_INTERVAL`: How often to clean up old files
|
||||
- `ALLOWED_DOMAINS`: Restrict to specific video platforms
|
||||
|
||||
### System Requirements
|
||||
- Python 3.6+ (for yt-dlp)
|
||||
- yt-dlp installed: `pip install yt-dlp` or `brew install yt-dlp`
|
||||
- ffmpeg installed: `brew install ffmpeg` (for audio conversion)
|
||||
|
||||
## Examples
|
||||
|
||||
### Download MP4 Video
|
||||
```typescript
|
||||
const response = await fetch('/api/download', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
url: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ',
|
||||
format: 'mp4',
|
||||
formatType: 'video'
|
||||
})
|
||||
});
|
||||
```
|
||||
|
||||
### Download MP3 Audio
|
||||
```typescript
|
||||
const response = await fetch('/api/download', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
url: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ',
|
||||
format: 'mp3',
|
||||
formatType: 'audio'
|
||||
})
|
||||
});
|
||||
```
|
||||
|
||||
## Limitations
|
||||
- Requires yt-dlp and ffmpeg to be installed on the server
|
||||
- No automatic file cleanup (files accumulate in public/downloads)
|
||||
- No file size limits or rate limiting
|
||||
- No user authentication or download history
|
||||
|
||||
## Future Improvements
|
||||
- Add file cleanup job for old downloads
|
||||
- Add download progress tracking
|
||||
- Add download history for users
|
||||
- Add file size limits and validation
|
||||
- Add support for playlists
|
||||
- Add video quality selection (720p, 1080p, etc.)
|
||||
Reference in New Issue
Block a user