<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Chaitanya Pareek</title>
    <description>The latest articles on DEV Community by Chaitanya Pareek (@chaitaneya).</description>
    <link>https://dev.to/chaitaneya</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4010000%2Fafa3d231-183f-4b32-9a6d-e0f07891949e.png</url>
      <title>DEV Community: Chaitanya Pareek</title>
      <link>https://dev.to/chaitaneya</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/chaitaneya"/>
    <language>en</language>
    <item>
      <title>I Built a Live Video Streaming Engine That Heals Itself</title>
      <dc:creator>Chaitanya Pareek</dc:creator>
      <pubDate>Wed, 01 Jul 2026 07:49:14 +0000</pubDate>
      <link>https://dev.to/chaitaneya/i-built-a-live-video-streaming-engine-that-heals-itself-3oji</link>
      <guid>https://dev.to/chaitaneya/i-built-a-live-video-streaming-engine-that-heals-itself-3oji</guid>
      <description>&lt;p&gt;&lt;em&gt;A side project that turned into the hardest client-side engineering I've ever done.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;I used to watch IPTV in my college mess hall — just open a website, pick a random channel, and zone out. No algorithm, no recommendations, no decisions. After long days when I had zero cognitive energy left, it was the perfect way to decompress — just watch whatever random broadcast was on, from wherever in the world. One day I thought: what if I turned this into something interactive? A game where you watch a live broadcast and try to guess which country it's from.&lt;/p&gt;

&lt;p&gt;The game part was easy. The streaming part nearly broke me.&lt;/p&gt;

&lt;p&gt;This is not a post about a guessing game. This is about the engineering problems I ran into while trying to make thousands of unreliable, globally distributed live video streams work reliably in a browser — and how I solved each one.&lt;/p&gt;




&lt;h2&gt;
  
  
  Problem 1: Most Live Streams Don't Actually Work
&lt;/h2&gt;

&lt;p&gt;I source from &lt;code&gt;iptv-org&lt;/code&gt;, a community-maintained database of publicly available television streams. It has &lt;strong&gt;13,000+ entries&lt;/strong&gt;. Sounds great on paper.&lt;/p&gt;

&lt;p&gt;In practice, roughly 40% of those entries are dead at any given moment. Channels shut down, URLs change, servers go offline. If I just pick a random stream and load it, there's nearly a coin-flip chance the user stares at a black screen.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why this is hard:&lt;/strong&gt; There's no central authority telling you which streams are alive. The database updates periodically, but the actual server status changes minute by minute.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How I solved it:&lt;/strong&gt; I built a background validation pipeline that continuously tests streams before the user ever sees them. The system maintains a buffer of &lt;strong&gt;20 pre-validated, ready-to-play streams&lt;/strong&gt; at all times. When the user clicks "next channel," they get a stream that was already proven alive seconds ago. Zero loading screens, zero dead feeds.&lt;/p&gt;

&lt;p&gt;The validation loop runs on a 600ms throttle to avoid flooding the network. When the buffer is full, it sleeps for 5 seconds and checks again.&lt;/p&gt;




&lt;h2&gt;
  
  
  Problem 2: A Stream Can Look Alive But Still Be Broken
&lt;/h2&gt;

&lt;p&gt;This was the bug that took me the longest to figure out.&lt;/p&gt;

&lt;p&gt;HLS streams (the format most IPTV uses) work in two steps: first, the browser downloads a &lt;code&gt;.m3u8&lt;/code&gt; manifest file (an index of video segments), then it downloads the actual &lt;code&gt;.ts&lt;/code&gt; video segments. Many servers set CORS headers on the manifest but &lt;strong&gt;not on the video segments&lt;/strong&gt;. Or they use geo-IP restrictions that block the segments based on your location.&lt;/p&gt;

&lt;p&gt;The result: the manifest loads perfectly. You think you have a working stream. But when the player tries to play actual video — nothing. Black screen.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why this is hard:&lt;/strong&gt; A simple "does this URL return a 200?" check is useless. The manifest responds fine. The failure only happens at the fragment level, which you can only discover by actually attempting playback.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How I solved it:&lt;/strong&gt; I built a &lt;strong&gt;Dual-Gate Validation&lt;/strong&gt; system:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Gate 1 (Manifest Check):&lt;/strong&gt; I spin up a headless &lt;code&gt;Hls.js&lt;/code&gt; instance attached to a hidden &lt;code&gt;&amp;lt;video&amp;gt;&lt;/code&gt; element. When the &lt;code&gt;MANIFEST_PARSED&lt;/code&gt; event fires, I know the manifest is accessible.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gate 2 (Fragment Check):&lt;/strong&gt; I don't stop there. I actually start silent playback and wait for the &lt;code&gt;FRAG_LOADED&lt;/code&gt; event — meaning a real video segment was downloaded and decoded. Only when both gates pass within 5 seconds do I consider the stream valid.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This single design decision eliminated an entire class of "it loaded but won't play" bugs.&lt;/p&gt;




&lt;h2&gt;
  
  
  Problem 3: One Bad Server Wastes Hundreds of Validation Attempts
&lt;/h2&gt;

&lt;p&gt;Once I had dual-gate validation working, I noticed a pattern: when a stream from &lt;code&gt;cdn.example.com&lt;/code&gt; fails due to CORS, every other stream on that same CDN fails too. They share the same server configuration. I was wasting 5 seconds per stream, testing dozens of URLs that were all going to fail for the same reason.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why this is hard:&lt;/strong&gt; The failure isn't at the URL level — it's at the domain level. You need to recognize patterns across failures, not just handle them individually.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How I solved it:&lt;/strong&gt; I built a &lt;strong&gt;domain-level CORS blocklist&lt;/strong&gt; that acts as a circuit breaker for entire infrastructure clusters.&lt;/p&gt;

&lt;p&gt;When a stream fails due to CORS or network errors, I extract the hostname, and blocklist the entire domain. Before any future validation attempt, I check the candidate's hostname against an in-memory &lt;code&gt;Set&lt;/code&gt; — O(1) lookup, zero network requests wasted.&lt;/p&gt;

&lt;p&gt;The blocklist is persisted to &lt;strong&gt;IndexedDB&lt;/strong&gt; so it survives page reloads. Over a single session, the system rapidly eliminates clusters of broken infrastructure. After 10 minutes of use, candidate selection becomes dramatically faster because all the known-bad domains are already filtered out.&lt;/p&gt;




&lt;h2&gt;
  
  
  Problem 4: The System Needs to Learn Which Streams Are Reliable
&lt;/h2&gt;

&lt;p&gt;Random selection from 13,000 streams is wasteful. Some channels have been reliably online for months. Others are flaky — they work sometimes and fail randomly. I needed the system to &lt;strong&gt;prioritize proven reliable streams&lt;/strong&gt; without me manually curating a list.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why this is hard:&lt;/strong&gt; You can't just pick the "best" streams and hardcode them. Stream reliability changes over time. You need a system that adapts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How I solved it:&lt;/strong&gt; I built a &lt;strong&gt;telemetry-driven health scoring system&lt;/strong&gt;. Every stream gets a health score (0–100), stored in IndexedDB:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;New/untested streams start at 60 (neutral-positive, worth trying)&lt;/li&gt;
&lt;li&gt;Successful dual-gate validation: &lt;strong&gt;+20 points&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Failed validation: &lt;strong&gt;-25 points&lt;/strong&gt; (harsh penalty, by design)&lt;/li&gt;
&lt;li&gt;CORS failures additionally flag the stream as &lt;code&gt;corsCompatible: false&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The pre-warming loop doesn't pick streams randomly — it uses &lt;strong&gt;weighted random selection&lt;/strong&gt; where each stream's probability of being chosen is proportional to its health score. Reliable feeds naturally float to the top. Unreliable ones sink but aren't completely eliminated (minimum weight of 5 allows occasional retries in case they've been fixed).&lt;/p&gt;

&lt;p&gt;The result: the longer someone uses the app, the better the stream selection gets. It's a self-improving system.&lt;/p&gt;




&lt;h2&gt;
  
  
  Problem 5: What Happens When Everything Fails at Once?
&lt;/h2&gt;

&lt;p&gt;Network goes down. ISP throttles connections. The iptv-org data has a catastrophically bad batch. Whatever the reason, sometimes the player hits a streak of failures that the normal recovery path can't handle. Without protection, the app would spin endlessly trying dead streams.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why this is hard:&lt;/strong&gt; You can't just retry forever. But you also can't just give up and show an error screen. You need a middle ground that protects the user experience while the system recovers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How I solved it:&lt;/strong&gt; I implemented a &lt;strong&gt;three-state circuit breaker&lt;/strong&gt; (borrowed from distributed systems design):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CLOSED&lt;/strong&gt; (normal): Streams play normally. If 2+ playback errors occur within a 5-second window, the breaker trips.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OPEN&lt;/strong&gt; (tripped): All playback halts for 3 seconds. The system stops trying to load new streams entirely, giving transient issues time to clear.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HALF-OPEN&lt;/strong&gt; (recovery): The system loads one of 6 hardcoded "safe" fallback streams (DW, France 24, Al Jazeera — channels with near-100% uptime). If it plays cleanly for 10 seconds, the breaker resets. If it fails again, it cycles back to OPEN with a different fallback.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This means even in the worst-case scenario, the user always lands on a working stream within seconds. The system self-heals.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Architecture in One Sentence
&lt;/h2&gt;

&lt;p&gt;A background pipeline that fetches 13,000 IPTV streams, validates them through a dual-gate check in a headless video player, scores them with telemetry, blocklists broken domains, maintains a pre-warmed buffer of 20 ready-to-play streams, and is protected by a circuit breaker — all running entirely client-side in the browser, with zero backend servers.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7fsj6tzz7m20dz1dnp33.png" alt="architecture diagram" width="800" height="856"&gt;
&lt;/h2&gt;

&lt;h2&gt;
  
  
  What I'd Do Differently
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;This is a craft project, not a product.&lt;/strong&gt; My seniors rightly pointed out that there's no strong "why" for an end user — why would someone in India watch a random TV channel in a language they don't understand? Fair point.&lt;/p&gt;

&lt;p&gt;But the engineering problems were real. Handling unreliable distributed systems, building self-healing pipelines, implementing circuit breakers, designing telemetry-driven selection algorithms — these are the same problems you'd face at any company dealing with third-party integrations, video infrastructure, or distributed data.&lt;/p&gt;

&lt;p&gt;The game was the wrapper. The engineering was the point.&lt;/p&gt;




&lt;h2&gt;
  
  
  Tech Stack
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Technology&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Core&lt;/td&gt;
&lt;td&gt;React 19, TypeScript, Vite&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3D Rendering&lt;/td&gt;
&lt;td&gt;Three.js, React Three Fiber&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Video Playback&lt;/td&gt;
&lt;td&gt;Hls.js (headless for validation, visible for playback)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Persistent Storage&lt;/td&gt;
&lt;td&gt;IndexedDB (localforage)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;State Management&lt;/td&gt;
&lt;td&gt;Zustand&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;p&gt;&lt;em&gt;If you're interested in the code:&lt;br&gt;
&lt;a href="https://github.com/Chaitaneya/IDKstream.git" rel="noopener noreferrer"&gt;github.com/Chaitaneya/Geo-Stream&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Try the raw engine:&lt;a href="https://idk-stream-theta.vercel.app/" rel="noopener noreferrer"&gt;Live Demo&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Play the game I built on top of it:&lt;a href="https://geo-stream-ashy.vercel.app/" rel="noopener noreferrer"&gt;Try Geo-Stream&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you've solved similar problems with unreliable third-party streams or built self-healing pipelines, I'd love to hear how you approached it.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>architecture</category>
      <category>showdev</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
