Software engineer — backend & product
Modelling a YouTube archive so a video is canonical and its appearances are not — and why that made everything else simple.
Python · PostgreSQL · Gemini · 2025
Python CLI, PostgreSQL · 2025
Acervo is an incremental crawler that turns YouTube channels and playlists into a local, searchable knowledge base — transcripts, summaries, and classification, built up over repeated runs rather than one big import. The whole system rests on a single modelling decision made early: a video is not the same kind of thing as its appearance in a collection.
The same video can show up in a channel's uploads and in an unrelated playlist, at different positions, discovered on different runs. If "this video is in this collection" and "this video exists, with this transcript and this summary" are treated as one record, importing a new playlist that happens to contain an already-known video either duplicates the video's expensive data (a wasted re-fetch and re-summarize) or silently merges two collections' organization into one.
Video is the canonical record, identified by video_id — it owns the
transcript, the summary, and processing state, and that data is reused
wherever the same video appears. CollectionItem records the separate fact
that a video showed up in a specific channel or playlist, at a specific
position, with whatever payload that source provided. Each crawl run also
keeps the raw provider observation it produced, so a playlist import doesn't
overwrite or blend with what a channel import already recorded for the same
video.
Separate the video from its appearance in a collection
Approval gates before spending on summarization
Gemini video as a transcript fallback, not the default path
Preserving each run's raw provider observation, instead of just merging new data into the existing record, was added specifically because an early version conflated "the video's data" with "what this particular API response said" — which meant a playlist re-crawl could quietly overwrite context that a channel crawl had already established. Keeping the raw observation per run, scoped to the collection that produced it, was the fix.
The organize-by-theme step still needs approval before it runs, same as summarization, and it's the least developed part of the system — I'd rather finish making that step observable (what it changed, why) before extending it further.