@page "/" @inject HttpClient Http @inject IPdfSaver PdfSaver @using VideoStudy.Shared @using System.Net.Http.Json @using System.Text.Json @using System.Threading // Added for Cancellation VideoStudy - Video Analysis

VideoStudy (Native)

Transforme videos em apostilas inteligentes com IA

@if (activeTab == "youtube") {
} @if (videoInfo != null) {
@if (!string.IsNullOrEmpty(videoInfo.ThumbnailUrl)) { Thumbnail }
@videoInfo.Title
@videoInfo.Author @videoInfo.Duration.ToString(@"hh\:mm\:ss")
}
@if (videoInfo == null) { } else {
}
@if (isProcessing || currentStep > 0) {
@statusMessage
} @if (logs.Count > 0) {
Execution Logs @logs.Count items @(showLogs ? "v" : ">")
@if (showLogs) {
@foreach (var log in logs) {
[@log.Timestamp:HH:mm:ss] @log.Message
}
}
}
@code { private string activeTab = "youtube"; private bool isProcessing = false; private bool isFetchingInfo = false; private int progress = 0; private int currentStep = 0; private string statusMessage = "Ready"; private bool showLogs = false; private List logs = new(); private string videoUrl = string.Empty; private string selectedLanguage = "en"; private string selectedOutputLanguage = "pt"; private VideoInfo? videoInfo; private class LogEntry { public DateTime Timestamp { get; set; } = DateTime.Now; public string Message { get; set; } = string.Empty; } private void ToggleLogs() => showLogs = !showLogs; private void AddLog(string message, int? eventProgress = null) { logs.Insert(0, new LogEntry { Message = message }); if (eventProgress.HasValue) progress = eventProgress.Value; StateHasChanged(); } private void ClearVideoInfo() { videoInfo = null; } private async Task FetchVideoInfo() { if (string.IsNullOrWhiteSpace(videoUrl)) return; isFetchingInfo = true; showLogs = true; try { AddLog("Buscando informacoes do video..."); var response = await Http.GetAsync($"api/video-info?url={Uri.EscapeDataString(videoUrl)}"); if (!response.IsSuccessStatusCode) { var error = await response.Content.ReadAsStringAsync(); throw new Exception($"API Error: {error}"); } videoInfo = await response.Content.ReadFromJsonAsync( new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); if (videoInfo != null) AddLog($"Video encontrado: {videoInfo.Title} ({videoInfo.Duration:hh\\:mm\\:ss})"); } catch (Exception ex) { AddLog($"Erro: {ex.Message}"); } finally { isFetchingInfo = false; } } private async Task StartAnalysis() { isProcessing = true; progress = 0; currentStep = 0; logs.Clear(); showLogs = true; CancellationTokenSource? cts = null; try { currentStep = 1; statusMessage = "Iniciando análise..."; AddLog("🚀 Enviando requisição para a API...", 5); var request = new AnalysisRequest { VideoUrl = videoUrl, Language = selectedLanguage, OutputLanguage = selectedOutputLanguage, Mode = "native" }; cts = new CancellationTokenSource(); var cancellationToken = cts.Token; var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, "api/analyze") { Content = JsonContent.Create(request) }; using var response = await Http.SendAsync(httpRequestMessage, HttpCompletionOption.ResponseHeadersRead, cancellationToken); if (!response.IsSuccessStatusCode) { var error = await response.Content.ReadAsStringAsync(); throw new Exception($"API Error ({response.StatusCode}): {error}"); } var stream = response.Content.ReadFromJsonAsAsyncEnumerable(new JsonSerializerOptions { PropertyNameCaseInsensitive = true }, cancellationToken); await foreach (var analysisEvent in stream.WithCancellation(cancellationToken)) { if (analysisEvent == null) continue; if (analysisEvent.IsError) { throw new Exception($"Erro da API: {analysisEvent.Message}"); } AddLog(analysisEvent.Message, analysisEvent.ProgressPercentage); statusMessage = analysisEvent.Message; progress = analysisEvent.ProgressPercentage; StateHasChanged(); if (analysisEvent.Result != null) { var result = analysisEvent.Result; AddLog("✅ Análise concluída!", 100); statusMessage = "Pronto!"; if (result.PdfData != null && result.PdfData.Length > 0) { AddLog("Salvando PDF..."); var fileName = $"VideoStudy_{result.VideoTitle ?? "Tutorial"}_{DateTime.Now:yyyyMMdd_HHmmss}.pdf"; // Remove invalid filename chars fileName = string.Join("_", fileName.Split(Path.GetInvalidFileNameChars())); var savedPath = await PdfSaver.SavePdfAsync(result.PdfData, fileName); if (savedPath != null) AddLog($"✓ PDF salvo: {savedPath}"); else AddLog("⚠️ Salvamento do PDF cancelado pelo usuário"); } else { AddLog("⚠️ Nenhum dado de PDF retornado da API"); } break; } } } catch (OperationCanceledException) { AddLog("⏸️ Operação cancelada."); statusMessage = "Cancelado"; } catch (Exception ex) { AddLog($"❌ Erro: {ex.Message}"); statusMessage = "Erro"; } finally { isProcessing = false; videoInfo = null; cts?.Dispose(); } } }