Scraper de canales de YouTube hacia notas Markdown para base de conocimiento (Obsidian-ready), con plataforma web local. Engine + CLI (Workstream A): - Modular pipeline: discover/extract/parse/chapters/render/store + ratelimit - SQLite store con migración idempotente: FTS5 (transcript search), columnas de metadata enriquecida, tablas cookies_meta y scrape_jobs - Módulos: segments, cookies (Netscape vault), export (json/csv/srt/html), analysis (word freq/timeline/wordcloud), monitor (watch loop), pipeline - CLI Click group: search, export, audio, channels, watch, analyze, re-render - Fix del bug de scoping de cookies en cli.py Webapp local (Workstream B): - FastAPI backend: dashboard, channels, videos facetado, transcript, search FTS, analysis, scrape jobs con SSE, cookies drag-and-drop, exports, folders (abrir en OS), tools (re-render, formato) - SPA no-build (Alpine.js + Tailwind + Chart.js por CDN): 9 vistas, tema dark command-center con acento rojo→rosa, cookie vault drag-drop, consola de scrapeo con progreso live vía SSE Launcher + subagentes (Workstream C): - start-server.bat / stop-server.bat con auto port-scan + browser open - .opencode/agent/webapp-builder.md + .opencode/goals/webapp-build.md Tests: 38 pytest verdes. Sin funcionalidad de IA (enfoque data-mining).
85 lines
3.3 KiB
PowerShell
85 lines
3.3 KiB
PowerShell
$ErrorActionPreference = 'Stop'
|
|
$root = Split-Path -Parent $PSScriptRoot
|
|
Set-Location -LiteralPath $root
|
|
|
|
Write-Host ""
|
|
Write-Host " [yt-scraper] iniciando servidor local..." -ForegroundColor Cyan
|
|
|
|
if (-not (Test-Path '.run')) { New-Item -ItemType Directory -Path '.run' | Out-Null }
|
|
|
|
# Already running?
|
|
if (Test-Path '.run\server.info') {
|
|
$firstLine = (Get-Content '.run\server.info' -TotalCount 1)
|
|
$existingPort = ($firstLine -split '\s+')[0]
|
|
try {
|
|
$r = Invoke-WebRequest -Uri "http://localhost:$existingPort/healthz" -UseBasicParsing -TimeoutSec 2
|
|
if ($r.Content -match 'ok') {
|
|
Write-Host " [ok] servidor ya activo en el puerto $existingPort" -ForegroundColor Green
|
|
Start-Process "http://localhost:$existingPort"
|
|
exit 0
|
|
}
|
|
} catch {}
|
|
}
|
|
|
|
# Collect candidate free ports scanning from 8000.
|
|
$candidates = @()
|
|
foreach ($p in 8000..8100) {
|
|
try {
|
|
$listener = [System.Net.Sockets.TcpListener]::new([System.Net.IPAddress]::Loopback, $p)
|
|
$listener.Start(); $listener.Stop()
|
|
$candidates += $p
|
|
if ($candidates.Count -ge 8) { break }
|
|
} catch {}
|
|
}
|
|
if ($candidates.Count -eq 0) {
|
|
Write-Host " [error] no se encontro ningun puerto libre (8000-8100)" -ForegroundColor Red
|
|
exit 2
|
|
}
|
|
|
|
# Launch uvicorn DETACHED in its own persistent minimized console window, logging to .run/server.log.
|
|
# The `cmd /c` window is an independent console: it survives this launcher exiting.
|
|
$launched = $false
|
|
$proc = $null
|
|
$port = 0
|
|
foreach ($candidate in $candidates) {
|
|
# clear previous log
|
|
Remove-Item '.run\server.log' -Force -ErrorAction SilentlyContinue
|
|
$cmdLine = '/c python -m uvicorn yt_scraper.webapp.app:app --host 127.0.0.1 --port ' + $candidate + ' --log-level info > .run\server.log 2>&1'
|
|
$proc = Start-Process -FilePath 'cmd.exe' -ArgumentList $cmdLine -WorkingDirectory $root -WindowStyle Minimized -PassThru
|
|
Set-Content -Path '.run\server.info' -Value "$candidate $($proc.Id) $(Get-Date -Format o)" -Encoding ASCII
|
|
|
|
$ok = $false
|
|
for ($i = 0; $i -lt 40; $i++) {
|
|
Start-Sleep -Milliseconds 500
|
|
try {
|
|
$r = Invoke-WebRequest -Uri "http://localhost:$candidate/healthz" -UseBasicParsing -TimeoutSec 2
|
|
if ($r.Content -match 'ok') { $ok = $true; break }
|
|
} catch {}
|
|
}
|
|
if ($ok) { $port = $candidate; $launched = $true; break }
|
|
|
|
# failed on this port — show why from the log, then try the next candidate
|
|
Stop-Process -Id $proc.Id -Force -ErrorAction SilentlyContinue
|
|
Remove-Item '.run\server.info' -Force -ErrorAction SilentlyContinue
|
|
}
|
|
|
|
if (-not $launched) {
|
|
Write-Host " [error] no se pudo iniciar el servidor." -ForegroundColor Red
|
|
if (Test-Path '.run\server.log') {
|
|
Write-Host " --- ultimo log del servidor ---" -ForegroundColor Yellow
|
|
Get-Content '.run\server.log' -Tail 25 | ForEach-Object { Write-Host " $_" }
|
|
} else {
|
|
Write-Host " instala dependencias: pip install -e `".[web]`"" -ForegroundColor Yellow
|
|
}
|
|
exit 3
|
|
}
|
|
|
|
Start-Process "http://localhost:$port"
|
|
Write-Host ""
|
|
Write-Host " [ok] servidor activo" -ForegroundColor Green
|
|
Write-Host " URL: http://localhost:$port"
|
|
Write-Host " PID: $($proc.Id) (ventana minimizada 'cmd' independiente)"
|
|
Write-Host " log: .run\server.log"
|
|
Write-Host " stop: stop-server.bat"
|
|
Write-Host ""
|