Files
yt-channel-scraper/tests/test_markdown_actions.py
urieljareth b3b27ce883 feat: cookies desde navegador, fallback watch-page y optimizacion integral del nucleo
Extraccion autenticada:
- import_from_browser (Brave) con fallback CDP headless para cookies app-bound v20
- extract_via_watch_page: GET plano + ytInitialPlayerResponse cuando yt-dlp falla
  con sesion logueada (members-only); regex y opener cacheados
- js_runtimes (node/deno/bun/quickjs) propagado a todos los ydl_opts
- rutas de Brave multiplataforma (Windows/macOS/Linux)

Webapp UX: chips de filtros removibles, skeleton loaders, estado de vista en URL,
memoria de scroll, copyMd/openMd, import de cookies desde navegador, no-cache de statics

Rendimiento:
- entorno Jinja2 cacheado por directorio de plantilla (antes 1 por nota)
- _rank_unranked con guarda (antes full-scan en cada arranque/import)
- upsert_videos con executemany; dashboard sin N+1 (GROUP BY + conteo de tags en SQL)
- thumbnails en paralelo (6 hilos, CDN ytimg); handlers bloqueantes -> def (threadpool)
- reconcile de arranque en hilo daemon: uvicorn arriba al instante (0.95s con 1503 md),
  healthz expone reconcile_done
- Store.transaction(): escrituras por video agrupadas (~6 commits -> 3)

Refactor: helpers unicos (extract_handle->discover, safe_dirname/filename->render,
order_pending->store, keep_ref->config, seconds_to_ts solo en segments);
re-render del CLI delega en pipeline.re_render_videos (retira huerfanos y marca done);
fuera wrappers muertos de segments.py
2026-09-10 00:32:19 -06:00

69 lines
2.2 KiB
Python

from __future__ import annotations
from pathlib import Path
from fastapi import FastAPI
from fastapi.testclient import TestClient
import pytest
from yt_scraper.config import Config
from yt_scraper.store import Store, VideoRef
from yt_scraper.webapp.api import build_router
from yt_scraper.webapp.jobs import JobManager
@pytest.fixture
def api_client(tmp_path: Path, monkeypatch):
db_path = tmp_path / "state.db"
md_root = tmp_path / "markdown"
md_root.mkdir()
store = Store(db_path)
cfg = Config(database_path=str(db_path), output_dir=str(md_root))
jobs = JobManager(store, cfg)
router = build_router(store, cfg, jobs)
app = FastAPI()
app.include_router(router)
client = TestClient(app)
return client, store, cfg, tmp_path
def test_get_and_open_markdown(api_client, monkeypatch):
client, store, cfg, tmp_path = api_client
store.upsert_channel("UC1", "@test", "Test Channel", 1)
store.upsert_videos([
VideoRef("vid1", "UC1", "Test Video", "https://www.youtube.com/watch?v=vid1")
])
# 1. Not generated yet -> 404
r_get = client.get("/api/videos/vid1/markdown")
assert r_get.status_code == 404
r_open = client.post("/api/videos/vid1/open-markdown")
assert r_open.status_code == 404
# 2. Create markdown file and mark done
md_dir = tmp_path / "markdown" / "Test Channel"
md_dir.mkdir(parents=True)
md_file = md_dir / "2026-08-23_test-video.md"
md_content = "# Test Video\n\nContent here"
md_file.write_text(md_content, encoding="utf-8", newline="\n")
rel_path = "markdown/Test Channel/2026-08-23_test-video.md"
store.mark_done("vid1", rel_path, "es", "auto", False)
# 3. GET markdown returns text
r_get = client.get("/api/videos/vid1/markdown")
assert r_get.status_code == 200
assert r_get.text.replace("\r\n", "\n") == md_content
# 4. POST open-markdown calls _open_in_os
opened_paths = []
from yt_scraper.webapp import api as api_mod
monkeypatch.setattr(api_mod, "_open_in_os", lambda p: opened_paths.append(str(p)))
r_open = client.post("/api/videos/vid1/open-markdown")
assert r_open.status_code == 200
assert len(opened_paths) == 1
assert str(md_file.resolve()) in [str(Path(p).resolve()) for p in opened_paths]