← Back to Projects

Content Summarizer

Python LLM yt-dlp ffmpeg multimodal Status: in progress

Overview

Short-form video is engineered to keep you scrolling. I constantly come across genuinely useful clips, but consume far too many to remember them. This tool turns that scrolling into something I keep: hand it a video and it returns a concise summary of the key points, whether that's the steps for a dish or the stretches from a workout I want in my routine.

The pipeline

01

Share content

Video shared from a social media app

02

Telegram bot

Bot receives the shared video link

03

Fetch video

yt-dlp downloads the source video

Current — with Gemini
04

Gemini analyzes

Native video input reads audio and visuals directly, then produces the summary

05

Summary in Telegram

Concise text summary returned to the chat

Alternative — non-video model
04

ffmpeg splits media

Extracts individual frames and separates the audio track

05

Whisper transcribes

Audio is sent to Whisper for transcription

06

LLM analyzes

Frames and transcript are sent to an LLM, which produces the summary

07

Summary in Telegram

Concise text summary returned to the chat

Both pipelines are the same at the core: a video is shared to Telegram, the video is downloaded, analyzed by an LLM, and the output is displayed in Telegram. The difference is a result of certain models being unable to digest video files, which is elaborated on below.

How the bot runs

The bot has no server and no website of its own. It's a single Python process that talks to Telegram's API, and understanding three pieces explains how the whole thing works.

Identity — BotFather & the token
A Telegram bot is registered through @BotFather, Telegram's own bot for creating bots. It hands back a secret token that uniquely identifies mine. Every request the script makes to Telegram is authenticated with that token — so it's treated exactly like the API keys it sits alongside: kept in an environment variable, never in the code or the repository.
Connection — polling, not a webhook
There are two ways a bot can hear from Telegram. A webhook needs a public, always-on server for Telegram to push messages to. Polling — what I use — flips that around: the script opens a long-lived connection and repeatedly asks Telegram "anything new?", so it needs no public address and runs fine from my own machine. It's the natural fit for a personal tool I start on demand.
Running it — a long-lived process
"Running the bot" means launching that Python process and leaving it alive. While it runs it holds the polling loop open and responds to every message; when it stops, the bot goes quiet. I start it with a shell alias so it's a single command, and the process handles messages one after another until I close it.

Inside the script

When a link arrives, the script routes it down one of two paths depending on where the video is from — a distinction that turned out to matter for efficiency.

  1. Detect the link. The message text is matched against patterns for Instagram and YouTube URLs. Anything that isn't a recognized link gets a gentle nudge back instead of being processed.
  2. Route by source. YouTube links are handed to Gemini as a URL — Gemini fetches and reads them itself, so nothing is downloaded. Instagram Reels can't be passed by URL, so they take the download path instead.
  3. Download (Instagram only). yt-dlp pulls the video into a temporary folder and also grabs metadata — title, caption, uploader — which gets folded into the prompt to give the model extra context.
  4. Hand to Gemini. A downloaded video is uploaded to Gemini's Files API; the script waits for it to finish processing, then asks for the summary. YouTube skips straight to this request.
  5. Reply, splitting if needed. The summary is sent back into the chat. Telegram caps messages at 4096 characters, so anything longer is split across several messages.
  6. Clean up. The temporary folder and its downloaded video are deleted whether the run succeeded or failed, so nothing accumulates on disk.

One deliberate detail: the download and Gemini calls are slow, blocking operations, so they're run off the main thread. That keeps the bot responsive — it can acknowledge a message and update its status ("⏳ Downloading…" → "🧠 Analyzing…") while the heavy work happens in the background.

Tool choices

Python
The whole ecosystem for this kind of work (yt-dlp, media handling, LLM SDKs) is Python-native, making Python an easy choice for the back-end.
yt-dlp
yt-dlp is compatible with a myriad of platofrms including the ones I use the most: Instagram and TikTok. It is core to this project: as long as yt-dlp can fetch the video, the pipeline works/analysis can be performed.
Gemini, over other models
Gemini accepts video natively, which enables the use of a more efficient pipeline. A non-video model forces a longer path — extract frames, transcribe audio separately, then recombine. Gemini reads audio and visuals in one step.
ffmpeg not used
Essential if I used a non-video model: it splits a video into frames and isolates the audio for transcription.

Design considerations

Sharing from social apps
The tool is only useful if triggering it is frictionless. Sharing straight to a Telegram bot adds just one button press from within any social app. My first idea — triggering summaries by sending a video to a second Instagram account — was blocked by platform restrictions, so Telegram became the clean alternative.
Message length
Summaries occasionally exceed Telegram's character limit, so the bot splits long output across multiple messages.
Multi-platform support
It began Reels-only, then generalized to Shorts, full YouTube videos, and TikTok. The only real constraints are yt-dlp support and Gemini's file-size limit.

What's next

The bigger goal is to collect everything the tool produces into a single app or access point, rather than leaving it scattered across Telegram messages. Nearer-term:

  • Tune the output to be less verbose.
  • Measure token and LLM usage across different video lengths.
  • Produce the summary in the video's own language (my mom being the motivating case).
© 2026 Terry.