VideoStudy/VideoStudy.UI/Pages/Library.razor
Ricardo Carneiro c49ec3d5a5 refactor: limpeza geral e troca de Puppeteer por FFmpeg
- Remove projetos mortos: VideoStudy.Native (MAUI), Controllers/LicenseController
- Remove serviços não usados: FFmpegService, HardwareIdService, LicenseManager,
  PdfGeneratorService, ScreenshotService, TranscriptionService do UI
- Remove dependências pesadas do UI: Whisper.net, YoutubeExplode, QuestPDF
- Remove PuppeteerSharp e SkiaSharp do API (150MB Chromium não é mais necessário)
- Screenshots agora usam FFmpeg diretamente (mais simples, mais confiável)
- YouTubeService reescrito para chamar /api/video-info em vez de YoutubeExplode
- Adiciona campo UserContext em AnalysisRequest (contexto livre do usuário)
- UI traduzida para português; aba de arquivo local removida (nunca funcionou)
- YouTubeProcessor simplificado: sem modo Advanced/Whisper
- GetYtDlpPath busca yt-dlp.exe subindo até 7 níveis de diretório
- Cookies do yt-dlp configuráveis via YtDlp:CookiesBrowser no appsettings
- Chave Groq agora lida de env var GROQ_API_KEY (appsettings.json sem segredos)
- VideoStudy.Linux (Photino) adicionado à solução como host multiplataforma
- yt-dlp atualizado de 2025.01.26 para 2026.03.17 (fix do nsig extraction)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-15 14:08:05 -03:00

150 lines
4.7 KiB
Plaintext

@page "/library"
@inject PersistenceService PersistenceService
@using VideoStudy.Shared
@using System.Diagnostics
<div class="container-fluid py-4">
<div class="d-flex justify-content-between align-items-center mb-4">
<h2 class="fw-bold text-dark">📚 Minha Biblioteca</h2>
@if (!string.IsNullOrEmpty(currentFolder))
{
<button class="btn btn-outline-secondary" @onclick="GoBack">
⬅️ Voltar
</button>
}
</div>
@if (string.IsNullOrEmpty(currentFolder))
{
<!-- MODO PASTAS -->
<div class="row g-3">
<!-- Pasta Geral (Padrão) -->
<div class="col-md-3">
<div class="card h-100 shadow-sm folder-card" @onclick='() => OpenFolder("Geral")'>
<div class="card-body text-center p-4">
<div class="display-1 mb-2">📁</div>
<h5 class="fw-bold">Geral</h5>
<small class="text-muted">@GetCount("Geral") arquivos</small>
</div>
</div>
</div>
<!-- Outras Pastas do Disco -->
@foreach (var folder in folders)
{
if (folder == "Geral") continue;
<div class="col-md-3">
<div class="card h-100 shadow-sm folder-card" @onclick='() => OpenFolder(folder)'>
<div class="card-body text-center p-4">
<div class="display-1 mb-2">📁</div>
<h5 class="fw-bold">@folder</h5>
<small class="text-muted">@GetCount(folder) arquivos</small>
</div>
</div>
</div>
}
</div>
}
else
{
<!-- MODO ARQUIVOS (DENTRO DA PASTA) -->
<h5 class="mb-3 text-muted">Pasta: <strong>@currentFolder</strong></h5>
<div class="list-group shadow-sm">
@foreach (var session in currentSessions)
{
<div class="list-group-item list-group-item-action d-flex align-items-center p-3">
<div class="me-3 fs-1">📄</div>
<div class="flex-grow-1">
<h6 class="mb-1 fw-bold">@session.Title</h6>
<small class="text-muted">
📅 @session.CreatedAt.ToString("g") •
<span class="text-truncate d-inline-block" style="max-width: 300px;">@session.FilePath</span>
</small>
</div>
<button class="btn btn-primary btn-sm px-4 fw-bold" @onclick="() => OpenPdf(session.FilePath)">
Abrir PDF ↗️
</button>
</div>
}
@if (!currentSessions.Any())
{
<div class="text-center p-5 text-muted">
<h5>Esta pasta está vazia 🕸️</h5>
</div>
}
</div>
}
</div>
<style>
.folder-card {
cursor: pointer;
transition: transform 0.2s, box-shadow 0.2s;
border: none;
background: #f8f9fa;
}
.folder-card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 20px rgba(0,0,0,0.1) !important;
background: #fff;
border: 1px solid #dee2e6;
}
</style>
@code {
private List<string> folders = new();
private List<VideoStudySession> allSessions = new();
private List<VideoStudySession> currentSessions = new();
private string? currentFolder = null;
protected override void OnInitialized()
{
LoadData();
}
private void LoadData()
{
// Ler estrutura física e banco
folders = PersistenceService.GetFolders();
if (!folders.Contains("Geral")) folders.Insert(0, "Geral"); // Garantir Geral
allSessions = PersistenceService.GetAllSessions();
}
private int GetCount(string folder)
{
return allSessions.Count(s => s.FolderName == folder);
}
private void OpenFolder(string folderName)
{
currentFolder = folderName;
currentSessions = allSessions.Where(s => s.FolderName == folderName).ToList();
}
private void GoBack()
{
currentFolder = null;
}
private void OpenPdf(string path)
{
try
{
if (File.Exists(path))
{
new Process
{
StartInfo = new ProcessStartInfo(path) { UseShellExecute = true }
}.Start();
}
}
catch
{
// Tratamento simples, idealmente mostraria um toast
}
}
}