feat: add Goldfish Recap YouTube summary PWA
YouTube subtitles via OpenRouter become persistent, shareable recaps with timestamp jump links, PIN-protected creation, and Traefik deploy. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Generate PNG icons from SVG for PWA."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import pathlib
|
||||
import struct
|
||||
import zlib
|
||||
|
||||
ROOT = pathlib.Path(__file__).resolve().parents[1]
|
||||
SVG = ROOT / "public" / "icon.svg"
|
||||
|
||||
|
||||
def _png_chunk(tag: bytes, data: bytes) -> bytes:
|
||||
return struct.pack(">I", len(data)) + tag + data + struct.pack(">I", zlib.crc32(tag + data) & 0xFFFFFFFF)
|
||||
|
||||
|
||||
def write_simple_png(path: pathlib.Path, size: int) -> None:
|
||||
"""Minimal orange/blue square PNG — no external deps."""
|
||||
raw_rows = []
|
||||
for y in range(size):
|
||||
row = b"\x00"
|
||||
for x in range(size):
|
||||
cx, cy = size / 2, size / 2
|
||||
dist = ((x - cx) ** 2 + (y - cy) ** 2) ** 0.5
|
||||
if dist < size * 0.42:
|
||||
row += bytes([255, 159, 67]) # orange fish body
|
||||
elif y < size * 0.15 or y > size * 0.92:
|
||||
row += bytes([11, 61, 92])
|
||||
else:
|
||||
row += bytes([11, 61, 92])
|
||||
raw_rows.append(row)
|
||||
compressed = zlib.compress(b"".join(raw_rows), 9)
|
||||
ihdr = struct.pack(">IIBBBBB", size, size, 8, 2, 0, 0, 0)
|
||||
png = b"\x89PNG\r\n\x1a\n"
|
||||
png += _png_chunk(b"IHDR", ihdr)
|
||||
png += _png_chunk(b"IDAT", compressed)
|
||||
png += _png_chunk(b"IEND", b"")
|
||||
path.write_bytes(png)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
out = ROOT / "public" / "icon-192.png"
|
||||
write_simple_png(out, 192)
|
||||
print(f"Wrote {out}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,19 @@
|
||||
CREATE TABLE IF NOT EXISTS recaps (
|
||||
video_id TEXT PRIMARY KEY,
|
||||
title TEXT NOT NULL,
|
||||
channel TEXT,
|
||||
thumbnail_url TEXT,
|
||||
duration_sec INTEGER,
|
||||
language TEXT,
|
||||
tldr TEXT NOT NULL,
|
||||
vibe_check TEXT,
|
||||
watch_verdict TEXT NOT NULL CHECK (watch_verdict IN ('watch', 'skim', 'skip')),
|
||||
goldfish_note TEXT,
|
||||
sections_json TEXT NOT NULL,
|
||||
transcript_hash TEXT,
|
||||
model TEXT,
|
||||
created_at TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_recaps_created_at ON recaps (created_at DESC);
|
||||
Reference in New Issue
Block a user