Update docs: new README, IIS guide, and production web.config
- Replaced README.md with a modern, production-focused version featuring quick start, architecture, workflow, troubleshooting, and security sections - Added DEPLOYMENT_GUIDE_IIS_Windows11.md with step-by-step IIS deployment instructions, including SSL, CORS, and permissions - Added version-controlled web.config files for API and Blazor app with HTTPS redirection, security headers, and SPA/static file support - Moved detailed yt-dlp integration notes to README_UPDATED.md for technical reference - Improves clarity, maintainability, and production readiness of documentation and deployment
This commit is contained in:
@@ -1,84 +0,0 @@
|
||||
# TuneRipper API
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Starting the API
|
||||
|
||||
**Option 1: Using the start script (Windows)**
|
||||
```cmd
|
||||
cd TuneRipper.Api
|
||||
start-api.bat
|
||||
```
|
||||
|
||||
**Option 2: Using the start script (Linux/Mac)**
|
||||
```bash
|
||||
cd TuneRipper.Api
|
||||
chmod +x start-api.sh
|
||||
./start-api.sh
|
||||
```
|
||||
|
||||
**Option 3: Manual start**
|
||||
```cmd
|
||||
cd TuneRipper.Api
|
||||
dotnet run
|
||||
```
|
||||
|
||||
### API Endpoints
|
||||
|
||||
Once running, the API will be available at:
|
||||
- **HTTPS**: https://localhost:7160
|
||||
- **HTTP**: http://localhost:5112
|
||||
|
||||
### Testing the API
|
||||
|
||||
1. **Start the API** using one of the methods above
|
||||
2. **Open the HTTP test file**: `TuneRipper.Api/api-tests.http`
|
||||
3. **Run the connectivity tests first** to verify the API is responding
|
||||
4. **Use the main API tests** once connectivity is confirmed
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
#### "This localhost page can't be found" errors:
|
||||
|
||||
1. **Check if API is running**:
|
||||
- Look for console output showing "Now listening on: https://localhost:7160"
|
||||
- If not running, start it using the methods above
|
||||
|
||||
2. **Try HTTP instead of HTTPS**:
|
||||
- Use `http://localhost:5112` instead of `https://localhost:7160`
|
||||
- Some development environments have HTTPS certificate issues
|
||||
|
||||
3. **Trust development certificates** (for HTTPS):
|
||||
```cmd
|
||||
dotnet dev-certs https --trust
|
||||
```
|
||||
|
||||
4. **Check port availability**:
|
||||
- Make sure ports 7160 and 5112 aren't used by other applications
|
||||
- You can change ports in `Properties/launchSettings.json`
|
||||
|
||||
#### HTTP test file variables not working:
|
||||
|
||||
1. **Copy job IDs manually**:
|
||||
- Run a POST request to start processing
|
||||
- Copy the `fileName` value from the response
|
||||
- Use it in the manual test sections
|
||||
|
||||
2. **Use the troubleshooting section**:
|
||||
- Start with connectivity tests
|
||||
- Use manual GUID replacements if variables fail
|
||||
|
||||
### API Documentation
|
||||
|
||||
When the API is running, you can access:
|
||||
- **Root endpoint**: https://localhost:7160/ (lists available endpoints)
|
||||
- **OpenAPI spec**: https://localhost:7160/openapi/v1.json
|
||||
- **Health check**: https://localhost:7160/api/health
|
||||
|
||||
### Development
|
||||
|
||||
The API includes:
|
||||
- Automatic reload on code changes (when using `dotnet run`)
|
||||
- Detailed logging in the console
|
||||
- CORS enabled for Blazor WebAssembly client
|
||||
- OpenAPI/Swagger support for API documentation
|
||||
@@ -1,296 +0,0 @@
|
||||
# TuneRipper API - yt-dlp Integration
|
||||
|
||||
## Overview
|
||||
|
||||
The TuneRipper API has been updated to use `yt-dlp.exe` for real YouTube video processing with progress monitoring. Videos are downloaded and converted to MP3 files, stored in the `wwwroot/downloads` directory with a GUID-based filename format, and served directly through the API.
|
||||
|
||||
## Setup
|
||||
|
||||
### Prerequisites
|
||||
1. **.NET 10** installed
|
||||
2. **yt-dlp.exe** placed in `TuneRipper.Api/wwwroot/yt-dlp.exe`
|
||||
3. **ffmpeg** available in PATH (required by yt-dlp for audio conversion)
|
||||
|
||||
### File Structure
|
||||
```
|
||||
TuneRipper.Api/
|
||||
??? wwwroot/
|
||||
? ??? yt-dlp.exe # YouTube downloader executable
|
||||
? ??? downloads/ # Downloaded MP3 files (auto-created)
|
||||
??? Controllers/
|
||||
??? Services/
|
||||
??? Program.cs
|
||||
```
|
||||
|
||||
## Filename Format
|
||||
|
||||
Downloaded files use the structured format: **`{jobId}_{title}.mp3`**
|
||||
|
||||
### Format Breakdown:
|
||||
- **`{jobId}`**: GUID identifier for the processing job (e.g., `550e8400-e29b-41d4-a716-446655440000`)
|
||||
- **`_{title}`**: Sanitized video title with spaces replaced by underscores
|
||||
- **`.mp3`**: Audio format extension
|
||||
|
||||
### Examples:
|
||||
- `550e8400-e29b-41d4-a716-446655440000_Rick_Astley_Never_Gonna_Give_You_Up.mp3`
|
||||
- `6ba7b810-9dad-11d1-80b4-00c04fd430c8_How_to_Build_a_Web_API.mp3`
|
||||
- `6ba7b811-9dad-11d1-80b4-00c04fd430c8_Amazing_Guitar_Solo_Performance.mp3`
|
||||
|
||||
### Benefits:
|
||||
- **Unique Identification**: GUID ensures no filename conflicts
|
||||
- **Direct Job Mapping**: Easy file lookup using job ID
|
||||
- **Human Readable**: Title part provides context
|
||||
- **System Friendly**: Sanitized for filesystem compatibility
|
||||
|
||||
### Title Sanitization:
|
||||
- Invalid filename characters are replaced with safe alternatives
|
||||
- Spaces become underscores (`_`)
|
||||
- Special characters: `< > | : * ? " /` are replaced with safe chars
|
||||
- Maximum title length: 50 characters
|
||||
- Fallback to "video" if title cannot be determined
|
||||
|
||||
## Key Changes
|
||||
|
||||
### 1. Program.cs Updates
|
||||
- Added `UseStaticFiles()` middleware for serving downloaded files
|
||||
- Added `AddHttpClient()` for VideoService HTTP requests
|
||||
- Updated logging and endpoint information
|
||||
|
||||
### 2. VideoService Updates
|
||||
- **GUID-Based Filenames**: Uses job ID as primary identifier in filename
|
||||
- **Title Sanitization**: Converts video titles to safe filenames
|
||||
- **Direct Job Mapping**: Files can be found using `{jobId}_*.*` pattern
|
||||
- **Real yt-dlp Integration**: Uses actual yt-dlp.exe with progress monitoring
|
||||
- **Progress Parsing**: Real-time progress from yt-dlp output streams
|
||||
- **Error Handling**: Comprehensive error handling with 5-minute timeout
|
||||
|
||||
### 3. VideoController Updates
|
||||
- Passes job ID to VideoService for filename generation
|
||||
- Uses actual yt-dlp processing instead of simulation
|
||||
- Stores downloaded file information with GUID-based naming
|
||||
- Returns real download URLs for completed files
|
||||
|
||||
### 4. DownloadController Updates
|
||||
- **Precise Job Lookup**: Uses `{jobId}_*.*` pattern for exact file matching
|
||||
- **User-Friendly Downloads**: Converts filenames back to readable format
|
||||
- **Example**: `550e8400-e29b-41d4-a716-446655440000_Rick_Astley_Never_Gonna_Give_You_Up.mp3` ? `Rick Astley Never Gonna Give You Up.mp3`
|
||||
- **Reliable File Operations**: No ambiguity in file identification
|
||||
- Serves actual MP3 files from `wwwroot/downloads/`
|
||||
- Proper MIME type detection for audio files
|
||||
|
||||
## API Workflow
|
||||
|
||||
### 1. Start Processing
|
||||
```http
|
||||
POST /api/video/process
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
|
||||
"format": "mp3",
|
||||
"quality": "128"
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "Processing started",
|
||||
"fileName": "550e8400-e29b-41d4-a716-446655440000",
|
||||
"downloadUrl": null,
|
||||
"videoDetails": null
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Monitor Progress
|
||||
```http
|
||||
GET /api/video/status/550e8400-e29b-41d4-a716-446655440000
|
||||
```
|
||||
|
||||
**Response (Processing):**
|
||||
```json
|
||||
{
|
||||
"percentageComplete": 45,
|
||||
"status": "Processing",
|
||||
"message": "Downloading audio...",
|
||||
"videoDetails": {
|
||||
"id": "dQw4w9WgXcQ",
|
||||
"title": "Rick Astley - Never Gonna Give You Up",
|
||||
"thumbnailUrl": "https://img.youtube.com/vi/dQw4w9WgXcQ/maxresdefault.jpg"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Get Final Result
|
||||
```http
|
||||
GET /api/video/result/550e8400-e29b-41d4-a716-446655440000
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "Video processed successfully",
|
||||
"fileName": "550e8400-e29b-41d4-a716-446655440000_Rick_Astley_Never_Gonna_Give_You_Up.mp3",
|
||||
"downloadUrl": "/downloads/550e8400-e29b-41d4-a716-446655440000_Rick_Astley_Never_Gonna_Give_You_Up.mp3",
|
||||
"videoDetails": { ... }
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Download File
|
||||
```http
|
||||
GET /api/download/550e8400-e29b-41d4-a716-446655440000
|
||||
```
|
||||
**Response:** Binary MP3 file download with user-friendly filename
|
||||
**Download Name:** `Rick Astley Never Gonna Give You Up.mp3`
|
||||
|
||||
**Alternative Static File Access:**
|
||||
```http
|
||||
GET /downloads/550e8400-e29b-41d4-a716-446655440000_Rick_Astley_Never_Gonna_Give_You_Up.mp3
|
||||
```
|
||||
|
||||
## File Management
|
||||
|
||||
### Download Directory
|
||||
- **Location**: `wwwroot/downloads/`
|
||||
- **Naming Pattern**: `{jobId}_{title}.ext`
|
||||
- **Job Lookup**: Files found using `Directory.GetFiles(dir, "{jobId}_*.*")`
|
||||
- **User Download**: Converted back to readable names
|
||||
- **Cleanup**: Files can be deleted by job ID
|
||||
|
||||
### File Serving Options
|
||||
1. **API Download**: Controlled access via `/api/download/{jobId}` (recommended)
|
||||
- Uses job ID for secure file lookup
|
||||
- Returns user-friendly filename
|
||||
- Proper error handling
|
||||
2. **Static Files**: Direct access via `/downloads/{actual_filename}`
|
||||
- Requires knowing the full filename
|
||||
- Less secure but faster
|
||||
3. **Content-Type**: Automatic detection based on file extension
|
||||
|
||||
### File Operations by Job ID
|
||||
- **Find**: `GET /api/download/info/{jobId}` - Get file metadata
|
||||
- **Download**: `GET /api/download/{jobId}` - Download the file
|
||||
- **Delete**: `DELETE /api/download/{jobId}` - Remove the file
|
||||
|
||||
## Progress Monitoring
|
||||
|
||||
The VideoService monitors yt-dlp output and translates it to progress updates:
|
||||
|
||||
- **5-15%**: Fetching video details
|
||||
- **15-70%**: Downloading audio (yt-dlp download progress × 0.7)
|
||||
- **70-85%**: Converting to MP3 (ffmpeg processing)
|
||||
- **85-95%**: Finalizing (cleanup)
|
||||
- **100%**: Complete
|
||||
|
||||
## Error Handling
|
||||
|
||||
### Common Errors:
|
||||
1. **yt-dlp.exe not found**: Ensure yt-dlp.exe is in wwwroot directory
|
||||
2. **ffmpeg not available**: Install ffmpeg and add to PATH
|
||||
3. **Invalid YouTube URL**: URL format validation
|
||||
4. **Download timeout**: 5-minute timeout for processing
|
||||
5. **File not found**: File may have been cleaned up or job ID invalid
|
||||
|
||||
### Error Response Format:
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"message": "Error description",
|
||||
"fileName": null,
|
||||
"downloadUrl": null,
|
||||
"videoDetails": null
|
||||
}
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### appsettings.json
|
||||
```json
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"TuneRipper.Api.Services.VideoService": "Debug"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### yt-dlp Arguments Used:
|
||||
- `--extract-audio`: Extract audio only
|
||||
- `--audio-format mp3`: Convert to MP3
|
||||
- `--audio-quality 0`: Best quality
|
||||
- `--no-playlist`: Single video only
|
||||
- `--no-warnings`: Clean output
|
||||
- `--newline`: Line-by-line progress
|
||||
- `--output "{jobId}_{title}.%(ext)s"`: Uses job ID-based filename
|
||||
|
||||
## Testing
|
||||
|
||||
### Manual Testing:
|
||||
1. Start the API: `dotnet run --project TuneRipper.Api`
|
||||
2. Use API testing tools or the Blazor client
|
||||
3. Check logs for yt-dlp progress
|
||||
4. Verify files in `wwwroot/downloads/` with GUID-based naming
|
||||
|
||||
### Example Test Files:
|
||||
```
|
||||
wwwroot/downloads/
|
||||
??? 550e8400-e29b-41d4-a716-446655440000_Rick_Astley_Never_Gonna_Give_You_Up.mp3
|
||||
??? 6ba7b810-9dad-11d1-80b4-00c04fd430c8_How_to_Build_a_Web_API.mp3
|
||||
??? 6ba7b811-9dad-11d1-80b4-00c04fd430c8_Amazing_Guitar_Solo_Performance.mp3
|
||||
```
|
||||
|
||||
### Health Check:
|
||||
```http
|
||||
GET /api/health
|
||||
```
|
||||
|
||||
### Job Listing:
|
||||
```http
|
||||
GET /api/video/jobs
|
||||
```
|
||||
|
||||
## Production Considerations
|
||||
|
||||
1. **File Storage**: Consider cloud storage for production
|
||||
2. **Cleanup Strategy**: Implement automatic file cleanup/retention using job completion timestamps
|
||||
3. **Security**: Job IDs provide secure file access (no directory traversal)
|
||||
4. **Performance**: Consider queue-based processing for high load
|
||||
5. **Monitoring**: Add detailed logging and metrics
|
||||
6. **Updates**: Keep yt-dlp.exe updated for compatibility
|
||||
7. **Scalability**: GUID-based naming prevents conflicts in distributed systems
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues:
|
||||
1. **Permissions**: Ensure API can write to wwwroot/downloads
|
||||
2. **Antivirus**: yt-dlp.exe may be flagged by antivirus
|
||||
3. **Network**: YouTube may block requests from some IPs
|
||||
4. **Format Support**: Some videos may not support audio extraction
|
||||
5. **Long Titles**: Titles are truncated to 50 characters for filesystem compatibility
|
||||
|
||||
### Debug Logging:
|
||||
Enable debug logging for VideoService to see detailed yt-dlp output:
|
||||
```json
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"TuneRipper.Api.Services.VideoService": "Debug"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### File Lookup Issues:
|
||||
- Verify job ID matches the GUID format
|
||||
- Check that files exist with the `{jobId}_` prefix
|
||||
- Look at directory contents if files are not found
|
||||
- Ensure proper case sensitivity on Linux systems
|
||||
|
||||
### Advantages of GUID-Based Naming:
|
||||
1. **Unique**: No filename conflicts possible
|
||||
2. **Secure**: Job ID acts as access token
|
||||
3. **Traceable**: Direct mapping from API calls to files
|
||||
4. **Scalable**: Works in distributed environments
|
||||
5. **Clean**: Easy cleanup by job ID pattern
|
||||
@@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<location path="." inheritInChildApplications="false">
|
||||
<system.webServer>
|
||||
<handlers>
|
||||
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
|
||||
</handlers>
|
||||
<aspNetCore processPath="dotnet" arguments=".\TuneRipper.Api.dll" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" hostingModel="inprocess">
|
||||
<environmentVariables>
|
||||
<environmentVariable name="ASPNETCORE_ENVIRONMENT" value="Production" />
|
||||
</environmentVariables>
|
||||
</aspNetCore>
|
||||
<rewrite>
|
||||
<rules>
|
||||
<rule name="Redirect to HTTPS" stopProcessing="true">
|
||||
<match url=".*" />
|
||||
<conditions>
|
||||
<add input="{HTTPS}" pattern="off" ignoreCase="true" />
|
||||
</conditions>
|
||||
<action type="Redirect" url="https://{HTTP_HOST}/{R:0}" redirectType="Permanent" />
|
||||
</rule>
|
||||
</rules>
|
||||
</rewrite>
|
||||
<!-- Security headers -->
|
||||
<httpProtocol>
|
||||
<customHeaders>
|
||||
<add name="X-Content-Type-Options" value="nosniff" />
|
||||
<add name="X-Frame-Options" value="DENY" />
|
||||
<add name="X-XSS-Protection" value="1; mode=block" />
|
||||
</customHeaders>
|
||||
</httpProtocol>
|
||||
</system.webServer>
|
||||
</location>
|
||||
</configuration>
|
||||
Reference in New Issue
Block a user