Removed /api/video/details endpoint; video details now fetched as first step of processing and included in progress/status responses. Updated backend models and controller logic to support integrated workflow and improved error handling. Refactored frontend to show video info and conversion progress in real time, removed legacy API calls, and enhanced UI/UX with responsive video info cards and progress bars. Updated documentation and example code to reflect new workflow.
9.6 KiB
9.6 KiB
TuneRipper API Service Usage Examples
Injecting the Service
In any Razor component, inject the API service:
@inject ITuneRipperApiService ApiService
Updated API Workflow
The API has been streamlined - video details are now fetched as the first step of processing, eliminating the need for a separate details endpoint.
New Workflow:
- Start Processing - Includes video details fetching as first step
- Monitor Status - Video details appear when progress reaches ~15%
- Get Final Result - Complete processing result with download URL
Usage Examples
1. Start Video Processing (includes video details fetching)
private async Task StartProcessingExample()
{
var request = new ProcessVideoRequest
{
Url = "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
Format = "mp3",
Quality = "128"
};
var response = await ApiService.StartProcessingAsync(request);
if (response?.Success == true)
{
var jobId = response.FileName; // This contains the job ID
await MonitorProcessingWithVideoDetails(jobId);
}
}
2. Monitor Processing Status (includes video details when available)
private async Task MonitorProcessingWithVideoDetails(string jobId)
{
YouTubeVideoDetails? videoDetails = null;
bool detailsReceived = false;
while (true)
{
var status = await ApiService.GetProcessingStatusAsync(jobId);
if (status == null) break;
Console.WriteLine($"Progress: {status.PercentageComplete}% - {status.Message}");
// Video details become available at ~15% progress
if (!detailsReceived && status.VideoDetails != null)
{
videoDetails = status.VideoDetails;
detailsReceived = true;
Console.WriteLine($"Video Details Received:");
Console.WriteLine($" Title: {videoDetails.Title}");
Console.WriteLine($" Author: {videoDetails.Author}");
Console.WriteLine($" Duration: {videoDetails.Duration}");
}
if (status.Status == "Completed" || status.Status == "Failed")
{
break;
}
await Task.Delay(2000); // Poll every 2 seconds
}
// Get final result
var result = await ApiService.GetProcessingResultAsync(jobId);
if (result?.Success == true)
{
Console.WriteLine($"Processing completed! Download: {result.DownloadUrl}");
}
}
3. Complete Processing Workflow
private async Task CompleteWorkflowExample()
{
try
{
// Step 1: Start processing
var request = new ProcessVideoRequest
{
Url = "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
Format = "mp3",
Quality = "128"
};
var startResponse = await ApiService.StartProcessingAsync(request);
if (startResponse?.Success != true)
{
Console.WriteLine($"Failed to start processing: {startResponse?.Message}");
return;
}
var jobId = startResponse.FileName;
Console.WriteLine($"Processing started with job ID: {jobId}");
// Step 2: Monitor progress and get video details
YouTubeVideoDetails? videoDetails = null;
bool processingComplete = false;
while (!processingComplete)
{
var status = await ApiService.GetProcessingStatusAsync(jobId);
if (status == null)
{
Console.WriteLine("Failed to get status");
break;
}
Console.WriteLine($"{status.PercentageComplete}%: {status.Message}");
// Capture video details when they become available
if (videoDetails == null && status.VideoDetails != null)
{
videoDetails = status.VideoDetails;
Console.WriteLine($"?? Video: {videoDetails.Title} by {videoDetails.Author}");
}
if (status.Status == "Completed")
{
processingComplete = true;
}
else if (status.Status == "Failed")
{
Console.WriteLine($"Processing failed: {status.Message}");
return;
}
if (!processingComplete)
{
await Task.Delay(2000);
}
}
// Step 3: Get final result
var result = await ApiService.GetProcessingResultAsync(jobId);
if (result?.Success == true)
{
Console.WriteLine($"? Success! File: {result.FileName}");
Console.WriteLine($"?? Download: {result.DownloadUrl}");
// Step 4: Download the file
var fileBytes = await ApiService.DownloadFileAsync(jobId);
if (fileBytes != null)
{
Console.WriteLine($"?? Downloaded {fileBytes.Length} bytes");
}
}
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
}
4. Download File
private async Task DownloadFileExample(string jobId)
{
var fileBytes = await ApiService.DownloadFileAsync(jobId);
if (fileBytes != null)
{
// In a Blazor component, you might trigger a download
// This would require additional JavaScript interop
Console.WriteLine($"Downloaded {fileBytes.Length} bytes");
}
}
5. Check API Health
private async Task CheckApiHealthExample()
{
var isHealthy = await ApiService.IsApiHealthyAsync();
if (isHealthy)
{
Console.WriteLine("API is healthy and responding");
}
else
{
Console.WriteLine("API is not responding or unhealthy");
}
}
6. Error Handling
private async Task ErrorHandlingExample()
{
try
{
var request = new ProcessVideoRequest
{
Url = "invalid-url",
Format = "mp3",
Quality = "128"
};
var response = await ApiService.StartProcessingAsync(request);
if (response?.Success != true)
{
Console.WriteLine($"Processing failed: {response?.Message}");
}
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
}
Configuration
The API service automatically uses the configuration from appsettings.json:
{
"ApiSettings": {
"BaseUrl": "https://localhost:7160",
"HttpBaseUrl": "http://localhost:5112",
"TimeoutSeconds": 30,
"EnableLogging": true,
"RetryAttempts": 3,
"RetryDelaySeconds": 2
}
}
API Endpoints
Current Endpoints:
- POST
/api/video/process- Start processing (includes video details fetching) - GET
/api/video/status/{jobId}- Get processing status (includes video details when available) - GET
/api/video/result/{jobId}- Get final processing result - GET
/api/video/jobs- List all processing jobs - GET
/api/download/{jobId}- Download converted file - GET
/api/health- Health check
Removed Endpoints:
GET/api/video/details?url={url}- Removed (now integrated into processing)
Complete Component Example
@page "/example"
@inject ITuneRipperApiService ApiService
<h3>Integrated Video Processing</h3>
<input @bind="youtubeUrl" placeholder="YouTube URL" />
<button @onclick="StartProcessing" disabled="@isProcessing">
@(isProcessing ? "Processing..." : "Convert Video")
</button>
@if (currentVideo != null)
{
<div class="video-info">
<h4>@currentVideo.Title</h4>
<p>By: @currentVideo.Author</p>
<p>Duration: @currentVideo.Duration</p>
</div>
}
@if (isProcessing)
{
<div class="progress">
<div class="progress-bar" style="width: @(progressPercent)%"></div>
<span>@progressMessage (@progressPercent%)</span>
</div>
}
@code {
private string youtubeUrl = "";
private bool isProcessing = false;
private int progressPercent = 0;
private string progressMessage = "";
private YouTubeVideoDetails? currentVideo = null;
private async Task StartProcessing()
{
if (string.IsNullOrWhiteSpace(youtubeUrl)) return;
isProcessing = true;
currentVideo = null;
progressPercent = 0;
try
{
// Start processing
var request = new ProcessVideoRequest { Url = youtubeUrl, Format = "mp3", Quality = "128" };
var response = await ApiService.StartProcessingAsync(request);
if (response?.Success == true)
{
await MonitorProgress(response.FileName);
}
}
finally
{
isProcessing = false;
}
}
private async Task MonitorProgress(string jobId)
{
while (isProcessing)
{
var status = await ApiService.GetProcessingStatusAsync(jobId);
if (status != null)
{
progressPercent = status.PercentageComplete;
progressMessage = status.Message ?? "Processing...";
// Video details appear at ~15%
if (currentVideo == null && status.VideoDetails != null)
{
currentVideo = status.VideoDetails;
}
if (status.Status == "Completed" || status.Status == "Failed")
{
break;
}
}
StateHasChanged();
await Task.Delay(2000);
}
}
}