from __future__ import annotations import csv import io import json from pathlib import Path import pytest from yt_scraper.store import Store, VideoRef from yt_scraper.parse import Segment from yt_scraper import segments, export, analysis from yt_scraper.render import build_filename_stem SAMPLE_MD = """--- video_id: abc123 title: "Vaporwave and nostalgia" channel: Alpha upload_date: 20240115 duration: 600 views: 1234 likes: 56 tags: ["vaporwave", "nostalgia"] thumbnail: http://img.test/abc.jpg --- # Vaporwave and nostalgia > [Ver en YouTube](https://www.youtube.com/watch?v=abc123) ## Transcripcion ### Intro (00:00) **00:15** · Bienvenidos al video sobre vaporwave. **00:32** · El vaporwave es una estetica muy interesante. ### Historia (01:15) **01:15** · El vaporwave nacio en los 2010s. **02:40** · dragon ball es un anime clasico. """ @pytest.fixture() def store(tmp_path): s = Store(tmp_path / "t.db") s.upsert_channel("UC1", "@alpha", "Alpha", 1) s.upsert_videos([VideoRef("abc123", "UC1", "Vaporwave and nostalgia", "https://y/watch?v=abc123", "20240115", 600)]) s.mark_done("abc123", "data/markdown/Alpha/x.md", "es", "auto", True) return s def test_parse_markdown_metadata(): parsed = segments.parse_markdown(SAMPLE_MD) assert parsed.metadata["video_id"] == "abc123" assert parsed.metadata["title"] == "Vaporwave and nostalgia" assert parsed.metadata["channel"] == "Alpha" assert len(parsed.segments) == 4 assert abs(parsed.segments[0].start - 15.0) < 0.01 assert "vaporwave" in parsed.segments[0].text.lower() chapters = parsed.chapters assert chapters[0]["title"] == "Intro" assert chapters[1]["title"] == "Historia" def test_backfill_from_markdown(store, tmp_path): md = tmp_path / "md" / "Alpha" / "vapor.md" md.parent.mkdir(parents=True) md.write_text(SAMPLE_MD, encoding="utf-8") n = segments.backfill_from_markdown(store, tmp_path / "md") assert n == 1 v = store.get_video("abc123") assert v.view_count == 1234 assert v.like_count == 56 assert json.loads(v.tags) == ["vaporwave", "nostalgia"] assert v.thumbnail == "http://img.test/abc.jpg" assert v.segments_json is not None segs = store.get_segments("abc123") assert len(segs) == 4 # search now works hits = store.search_segments("vaporwave") assert len(hits) >= 1 # idempotent n2 = segments.backfill_from_markdown(store, tmp_path / "md") assert n2 == 0 def test_ts_helpers(): assert segments.ts_to_seconds("01:30") == 90.0 assert segments.ts_to_seconds("1:02:03") == 3723.0 def test_export_json_csv(store, tmp_path): store.store_segments("abc123", [Segment(0.0, 2.0, "hello vaporwave")]) store.update_video_metadata("abc123", view_count=1234, tags=["vaporwave"]) j = export.export_json(store, "UC1", tmp_path / "out.json") data = json.loads(j.read_text(encoding="utf-8")) assert len(data["videos"]) == 1 assert data["videos"][0]["video_id"] == "abc123" c = export.export_csv(store, "UC1", tmp_path / "out.csv") with open(c, encoding="utf-8") as f: reader = csv.DictReader(f) rows = list(reader) assert rows[0]["video_id"] == "abc123" assert rows[0]["view_count"] == "1234" def test_export_srt(store, tmp_path): segs = [Segment(1.5, 3.5, "first line"), Segment(5.0, 7.0, "second line")] store.store_segments("abc123", segs) out = export.export_srt_video(store, "abc123", tmp_path / "x.srt") assert out is not None text = out.read_text(encoding="utf-8") assert "1\n" in text assert "00:00:01,500 --> 00:00:03,500" in text assert "first line" in text assert "second line" in text def test_export_html(store, tmp_path): store.update_video_metadata("abc123", thumbnail="http://t.test/x.jpg", tags=["vaporwave"]) out = export.export_html(store, "UC1", tmp_path / "g.html") html = out.read_text(encoding="utf-8") assert "abc123" in html assert "Gallery" in html def test_word_frequency(store): segs = [ Segment(0, 1, "vaporwave vaporwave nostalgia nostalgia nostalgia"), Segment(2, 3, "dragon dragon anime"), ] store.store_segments("abc123", segs) freq = analysis.word_frequency(store, "UC1", top=5) assert freq["nostalgia"] == 3 assert freq["vaporwave"] == 2 assert freq["dragon"] == 2 # stopwords filtered assert "y" not in freq assert "the" not in freq def test_term_timeline(store): segs = [Segment(0, 1, "vaporwave mentioned here")] store.store_segments("abc123", segs) tl = analysis.term_timeline(store, "vaporwave", "UC1") assert len(tl) == 1 assert tl[0][0] == "2024-01" def test_build_filename_stem(): # callers pass already-normalized dates; stem uses them verbatim stem = build_filename_stem("2024-01-01", "Hola Mundo!", "{upload_date}_{slug}") assert stem == "2024-01-01_hola-mundo"