Take YouTube at face value.
A browser extension that rewrites clickbait titles from the video's actual transcript,
replaces engineered thumbnails with a real frame from the video, and removes Shorts
entirely.
facethevalue.com · privacy · support the project
Every thumbnail on YouTube is a bid for your attention, and the bids keep escalating. Shocked faces, red arrows, capital letters, promises the video never keeps. Even honest creators package good work this way, because the algorithm rewards whoever grabs hardest. And when packaging individual videos isn't enough, there's Shorts: an infinite scroll engineered for the dopamine hit itself, built to keep you swiping instead of watching anything you actually chose.
Face Value takes those levers away. Titles say plainly what a video is, thumbnails are just a frame from the video, and Shorts disappears from the site entirely. What's left is a feed you choose from, not one that plays you.
- Clean titles. Rewritten from the video's transcript to say what it actually delivers. Hover any cleaned title to see the original.
- Clean thumbnails. A real frame extracted from the video itself.
- Hide Shorts. One toggle removes Shorts shelves, reels, and the sidebar button.
- Channel exceptions. Pause Face Value on channels you trust.
- No account, no analytics. The only thing sent off your device is the public video ids and titles on pages you view. Full details in the privacy policy.
Live streams and search results are intentionally left untouched: searching is deliberate navigation, and the feed is where the algorithm steers.
The extension only ever does one cheap batched read; all expensive work happens asynchronously behind a shared cache, so the whole system gets faster as more people use it. The serverless layer (API, cache, queues, CDN) is AWS; the two things that need a clean, non-datacenter IP to talk to YouTube (captions and video bytes) run on a flat-cost VPS behind a VPN and a fixed-fee ISP proxy pool.
flowchart LR
subgraph Browser
EXT[Content script]
end
subgraph AWS
API[API Gateway] --> RES[Resolver λ]
RES <--> DDB[(DynamoDB cache)]
RES -- miss --> Q1[[SQS titles]]
Q1 --> TW[Title worker λ<br/>oEmbed · gates · LLM rewrite]
TW --> DDB
TW -- passed gates --> Q2[[SQS thumbnails]]
S3[(S3 frames)] --> CF[CloudFront]
Q2 -. disabled fallback .-> THL[Thumb worker λ<br/>+ residential proxy]
ALM[CloudWatch alarms] --> SNS[SNS → email]
end
subgraph VPS["VPS (Hetzner) behind Mullvad + ISP proxy pool"]
CAP[Caption service<br/>yt-dlp android/ios · json3]
THP[Pooled thumb worker<br/>16 threads · yt-dlp web_embedded + deno · ffmpeg frame vote]
POOL[(Exit pools<br/>ISP IPs · Mullvad relays)]
CAP --- POOL
THP --- POOL
end
EXT -- "POST /titles (batch)" --> API
TW -- "GET /captions" --> CAP
TW --> LLM[qwen-flash → Gemini Flash-Lite]
Q2 --> THP
THP --> S3
THP --> DDB
EXT -- overlay img --> CF
POOL -. player + stream bytes .-> YT[(YouTube)]
Titles. The worker verifies the video via YouTube's public oEmbed API, asks the VPS caption service for the transcript (YouTube's own auto-captions, fetched through a clean exit), applies the demand gates (under a minute or under 10k views is left alone), and has a small LLM (qwen-flash, Gemini Flash-Lite as fallback) rewrite the title to state what the video actually contains. Grounding the rewrite in the transcript is the whole trick. If the caption lane is unhealthy the cure fails and retries rather than caching a title-only guess; a video that genuinely has no captions is rewritten from the title alone and marked as such.
Thumbnails. One pooled worker process runs sixteen jobs at a time: the yt-dlp
web_embedded client (with deno solving YouTube's JS challenge) exposes a direct
stream URL, the worker fetches only the first ~0.2 MB by Range request, and ffmpeg
scores every decodable frame on sharpness, entropy, and luminance in one pass and keeps
the best real frame. 720p output from a fifth of a megabyte, independent of video length.
An ffmpeg semaphore keeps the CPU part bounded; the network waits overlap. Each job
picks an exit from a pool of Mullvad relays and retries once through the ISP pool if
YouTube refuses the VPN exit.
Client. The content script masks cards with a CSS gate injected at
document_start, so the clickbait version is never painted. Results overlay YouTube's
own elements, and uncached videos resolve in a few seconds via bounded polling. Every
card has a hard deadline, so the page never hangs on our backend.
Operations. Prepaid, hard-capped LLM accounts; an AWS budget with a deny-all freeze action; CloudWatch alarms on queue age, thumb completions, and the share of cures that came back without a transcript, all to one SNS email.
extensions/ MV3 extension (chrome / edge / firefox, built from shared/)
src/resolver/ API Lambda: batch cache lookup + queueing (TypeScript)
src/worker/ Title worker: oEmbed + captions + gates + LLM rewrite (TypeScript)
src/thumbnail-worker/ Frame extraction pipeline: yt-dlp + ffmpeg (Python). Shared by the
VPS worker and the (disabled) Lambda container image
vps/ Everything that runs on the box: caption service, pooled thumb
worker, exit pools, health check, systemd units, README
template.yaml AWS SAM stack (API, queues, table, CDN, Lambdas, budget)
tools/ Local harnesses (LLM head-to-head, proxy cost, frame-vote A/B)
localworker/ Home-IP DLQ drainer (launchd)
The backend is one SAM stack plus one small Linux box. You need an AWS account, Docker
(for the container Lambda), and SSM SecureString parameters for the LLM keys and the
caption-service token; the header of template.yaml documents them.
sam build && sam deploy --guidedThe box needs WireGuard to a VPN with per-relay SOCKS exits (Mullvad works), a list of
fixed-fee ISP proxies, yt-dlp with yt-dlp-ejs and deno, and ffmpeg; vps/README.md
walks through the units and the exit pools. Point API_BASE in
extensions/shared/content.js at your endpoint, run extensions/build.sh, and load
the browser folder of your choice as an unpacked extension.
MIT. Fonts (Hanken Grotesk, Newsreader, JetBrains Mono) are bundled under the SIL Open Font License. yt-dlp and ffmpeg are used server side under their respective licenses.