<?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: Chris Cornell</title>
    <description>The latest articles on DEV Community by Chris Cornell (@chriscornell).</description>
    <link>https://dev.to/chriscornell</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%2F4092092%2F4c9740d7-edc6-4820-947d-67c624576585.png</url>
      <title>DEV Community: Chris Cornell</title>
      <link>https://dev.to/chriscornell</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/chriscornell"/>
    <language>en</language>
    <item>
      <title>Why live dubbing lags a sentence behind, and how dubbing from buffered audio fixes it</title>
      <dc:creator>Chris Cornell</dc:creator>
      <pubDate>Thu, 15 Oct 2026 03:46:53 +0000</pubDate>
      <link>https://dev.to/chriscornell/why-live-dubbing-lags-a-sentence-behind-and-how-dubbing-from-buffered-audio-fixes-it-5pe</link>
      <guid>https://dev.to/chriscornell/why-live-dubbing-lags-a-sentence-behind-and-how-dubbing-from-buffered-audio-fixes-it-5pe</guid>
      <description>&lt;p&gt;&lt;em&gt;Disclosure: I work on EarDub, a browser extension that dubs videos into other languages. This post is about a design problem we hit, not a product pitch, but the product comes up at the end.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you've tried a "real-time" video translator that listens to a video and speaks a translation, you've probably noticed the voice runs about one sentence behind the speaker. The person on screen finishes a thought, there's a pause, then the translation starts, and by then the speaker is already on the next point. On a talk or tutorial, that lag makes the dub feel like a bad simultaneous interpreter.&lt;/p&gt;

&lt;p&gt;This post explains why that happens and the approach we took to remove most of it for videos that have no captions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why listen-as-it-plays dubbing trails the picture
&lt;/h2&gt;

&lt;p&gt;A tool that captures audio as it comes out of the speakers can only work with what has already been played. To translate a sentence well, you need the whole sentence, because word order changes between languages: a German verb can land at the end, and a Japanese sentence can flip the order of a whole clause. So the pipeline has to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;wait for the speaker to finish the sentence,&lt;/li&gt;
&lt;li&gt;run speech recognition on it,&lt;/li&gt;
&lt;li&gt;translate it,&lt;/li&gt;
&lt;li&gt;synthesize speech,&lt;/li&gt;
&lt;li&gt;play it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Steps 2 to 4 take time, and step 1 alone guarantees the dub starts after the original sentence ends. That's the one-sentence lag. You can shorten it by translating partial sentences, but then the translation gets worse, which is the trade-off live interpreters face.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recorded video is different: the player already has the future
&lt;/h2&gt;

&lt;p&gt;For recorded video (not live streams), the browser's media player downloads ahead of the playhead. You can see this yourself in any page with a &lt;code&gt;&amp;lt;video&amp;gt;&lt;/code&gt; element:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;video&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;buffered&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;buffered&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;buffered&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;playing at&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentTime&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;buffered&lt;/code&gt; ranges usually extend well past &lt;code&gt;currentTime&lt;/code&gt; (&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/buffered" rel="noopener noreferrer"&gt;MDN: HTMLMediaElement.buffered&lt;/a&gt;). That audio exists before the viewer hears it. If you recognize speech from the audio the player has already loaded, you're working ahead of the viewer instead of behind them.&lt;/p&gt;

&lt;p&gt;That changes the pipeline:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Recognition runs on audio that's ahead of the playhead.&lt;/li&gt;
&lt;li&gt;Fragments are joined into complete sentences before translation, so you never have to translate half a thought.&lt;/li&gt;
&lt;li&gt;The translated sentence is synthesized and queued against the original timing, so it can start when the speaker starts that sentence.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The viewer gets a dub that starts with the speaker instead of a sentence later.&lt;/p&gt;

&lt;h2&gt;
  
  
  The details that matter in practice
&lt;/h2&gt;

&lt;p&gt;A few things we learned building this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stay a few sentences ahead, not the whole video.&lt;/strong&gt; Processing an entire video up front means a long wait before anything plays. Keeping a small window ahead of the playhead lets the first sentence start within seconds, and you pause when the video pauses.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Seeking resets the window.&lt;/strong&gt; When someone jumps to a new point, there's nothing prepared there yet, so the first sentence after a jump takes a few seconds. After that, the window refills ahead of playback.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Translated sentences don't always fit.&lt;/strong&gt; A translation can be longer than the original. Cutting it off sounds broken, so we let the voice speed up gently, capped at 1.45x, and never stop a sentence mid-word. At very high playback rates some sentences can't physically fit, so it's better to skip one than to cut one in half. That's why we recommend staying at 1.5x video speed or below while dubbing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Context beats word-for-word.&lt;/strong&gt; Translating each sentence with the video's title and surrounding sentences as context keeps names and technical terms consistent across a long tutorial.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Know what it can't do.&lt;/strong&gt; Working ahead requires a recorded video, so live streams are out. Loud music, overlapping speakers and heavy accents still cause recognition errors. One voice reads everyone, because recognized speech doesn't say who is talking.&lt;/p&gt;

&lt;h2&gt;
  
  
  Captions first, audio when there are none
&lt;/h2&gt;

&lt;p&gt;When a video already has captions, including auto-generated ones, you don't need speech recognition at all. The caption timing tells you exactly when each sentence starts. Audio recognition is the fallback for videos without captions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this ended up
&lt;/h2&gt;

&lt;p&gt;This is how EarDub handles videos without captions on YouTube, X, Bilibili and Gumroad (on its paid plans). Captioned videos work on the free plan, including Udemy and Coursera lectures. Audio sent for recognition is processed into text and not stored.&lt;/p&gt;

&lt;p&gt;If you want to try it, the user-facing details are on the &lt;a href="https://www.eardub.com" rel="noopener noreferrer"&gt;EarDub&lt;/a&gt; site, and the extension is on the &lt;a href="https://chromewebstore.google.com/detail/eardub-youtube-dubbing-vo/jmlcanhchdeaepjfgdefjmbfmlkfhpeh" rel="noopener noreferrer"&gt;Chrome Web Store&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I'd love to hear from anyone who has worked on similar timing problems, especially sentence segmentation for languages without spaces between words.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>ai</category>
      <category>a11y</category>
    </item>
    <item>
      <title>I Built a Free TikTok LIVE Recorder to Save Streams in 1 Weeks</title>
      <dc:creator>Chris Cornell</dc:creator>
      <pubDate>Wed, 23 Sep 2026 03:04:22 +0000</pubDate>
      <link>https://dev.to/chriscornell/i-built-a-free-tiktok-live-recorder-to-save-streams-in-1-weeks-5c32</link>
      <guid>https://dev.to/chriscornell/i-built-a-free-tiktok-live-recorder-to-save-streams-in-1-weeks-5c32</guid>
      <description>&lt;p&gt;Some live broadcasts are useful precisely because they happen in the moment: a creator explains a technique, answers questions, or shares an announcement. But a live is temporary. If there is no replay later, it can be difficult to revisit a detail or turn the broadcast into a highlight.&lt;/p&gt;

&lt;p&gt;I built Tok Live Recorder around a simple workflow: take a public TikTok LIVE link, record the broadcast, and keep an MP4 copy for later review or editing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why not just screen-record?
&lt;/h2&gt;

&lt;p&gt;Screen recording can be perfectly fine for a short clip. For a long broadcast, though, it ties the capture to a device and its current session. You may need to keep the screen awake, watch available storage, and deal with notifications or other on-screen elements in the recording.&lt;/p&gt;

&lt;p&gt;A dedicated capture workflow can remove some of that friction. Tok Live Recorder works in the browser: paste the LIVE link and start recording. Capture runs in the cloud, so it can continue if you close the tab. The result is saved as an MP4, which is straightforward to review or bring into a normal editing workflow. The web recorder is free and does not require an install or signup.&lt;/p&gt;

&lt;h2&gt;
  
  
  A small checklist for useful archives
&lt;/h2&gt;

&lt;p&gt;A recording is only useful if you can find it, play it, and use it responsibly. A few habits help:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Decide why you are saving it.&lt;/strong&gt; Is this for personal reference, a campaign recap, or editing a highlight? A clear purpose helps determine what to retain and who should have access.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check the source and permissions.&lt;/strong&gt; Record only streams you are allowed to save. A public stream is not automatically permission to repost someone else’s content. Follow platform rules and respect the creator’s wishes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verify the file.&lt;/strong&gt; After recording, check that it opens, the audio is present, and the beginning and end are there. For an important archive, sample a few points rather than assuming a completed download is usable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Label it consistently.&lt;/strong&gt; A simple creator–date–topic name makes a library much easier to search than a folder of files called “video-final-2.”&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Separate archiving from publishing.&lt;/strong&gt; Keeping a copy for reference is different from redistributing it. Before sharing clips, check rights, music, and anyone else’s privacy in the recording.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The point is not to save everything. It is to make it easier to keep the few broadcasts that matter, then review or edit them later without turning capture into another complicated production task.&lt;/p&gt;

&lt;p&gt;If you need a browser-based option specifically for TikTok LIVE, &lt;a href="https://tokliverecorder.com/" rel="noopener noreferrer"&gt;Tok Live Recorder&lt;/a&gt; is the tool I made for this workflow.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclosure: I work on Tok Live Recorder. AI assistance was used to draft and edit this post.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>tiktok</category>
    </item>
    <item>
      <title>From YouTube Captions to Synchronized Voice Dubbing: Practical Design Choices</title>
      <dc:creator>Chris Cornell</dc:creator>
      <pubDate>Wed, 23 Sep 2026 01:21:31 +0000</pubDate>
      <link>https://dev.to/chriscornell/from-youtube-captions-to-synchronized-voice-dubbing-practical-design-choices-2gj8</link>
      <guid>https://dev.to/chriscornell/from-youtube-captions-to-synchronized-voice-dubbing-practical-design-choices-2gj8</guid>
      <description>&lt;p&gt;Disclosure: I work on EarDub, the Chrome extension mentioned below. This post explains a practical viewing workflow and its limits.&lt;/p&gt;

&lt;p&gt;A translated subtitle is useful until the video asks you to watch something closely. In a software tutorial, a presenter may point to a menu while the caption describes the next step. Looking down to read the translation means missing the cursor movement. Voice dubbing can move that translation into the audio channel, but it works best when the source and timing are handled carefully.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with the source captions
&lt;/h2&gt;

&lt;p&gt;EarDub works with captioned YouTube videos. It reads the caption track and uses that text as the basis for translation and speech. This is different from uploading a video for transcription or editing a new dubbed video for distribution.&lt;/p&gt;

&lt;p&gt;The distinction matters. Auto-generated captions can contain names, numbers, and technical terms that are wrong. A natural-sounding translated voice does not repair a bad source. Before depending on a dub for a complex explanation, check the original captions around important statements.&lt;/p&gt;

&lt;p&gt;The current workflow is also limited to YouTube. A local video file, another video site, or a live stream is outside the supported path today. That boundary is part of choosing the right tool for the job.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reconstruct sentences before translating
&lt;/h2&gt;

&lt;p&gt;Caption tracks often break a sentence into pieces because they follow the pace of speech. Translating each piece by itself can separate a pronoun from the noun it refers to or a qualification from the claim it changes.&lt;/p&gt;

&lt;p&gt;A better input to the translator is a complete thought. EarDub merges caption fragments into sentences before translation and runs quality checks on the result. This aims to preserve context; it does not guarantee a perfect interpretation of humor, jargon, or ambiguous speech.&lt;/p&gt;

&lt;p&gt;This is especially relevant to tutorials. Compare these fragments:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Select the export option...&lt;br&gt;
...only after you have checked the source language.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If a system treats the first line as a complete instruction, it may miss the condition in the next line. Joining the sentence gives the translation a better chance to keep the sequence intact.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep speech aligned with the picture
&lt;/h2&gt;

&lt;p&gt;A dubbing voice has to be useful at the moment the viewer needs it. Speaking a correct translation several seconds late can be just as confusing as a poor translation. EarDub plays generated speech in sync with the YouTube video and realigns it when the viewer seeks to another point.&lt;/p&gt;

&lt;p&gt;Viewers can adjust original and dubbed audio separately. Leaving some original audio audible can preserve the speaker tone or environmental cues; reducing it can make the translated narration easier to understand. Bilingual subtitles provide another check when a term needs closer inspection.&lt;/p&gt;

&lt;p&gt;EarDub currently offers 75 dubbing languages and more than 300 neural voices. Voice choice is useful for comfort, but accuracy should still be judged against the source.&lt;/p&gt;

&lt;h2&gt;
  
  
  A sensible way to test it
&lt;/h2&gt;

&lt;p&gt;Pick a short captioned YouTube video in a subject you already know. Listen to the dub, compare a few sentences with the original captions, and try the volume controls. If the clip has specialized vocabulary, verify those terms directly rather than assuming the synthesized voice is authoritative.&lt;/p&gt;

&lt;p&gt;For learning, pause after a key step and repeat it in your own words. Dubbing changes how the explanation is delivered; it does not replace active practice. For high-stakes material, check the original and appropriate expert sources.&lt;/p&gt;

&lt;p&gt;EarDub has a free plan and optional paid plans for additional use. The &lt;a href="https://eardub.com/" rel="noopener noreferrer"&gt;EarDub website&lt;/a&gt; explains the current product and links to the Chrome extension. The useful question is whether listening helps you follow a captioned video more comfortably, while still giving you a way to verify what was said.&lt;/p&gt;

</description>
      <category>a11y</category>
      <category>tools</category>
    </item>
    <item>
      <title>How to Record and Save TikTok LIVE Streams (Free)tiktok</title>
      <dc:creator>Chris Cornell</dc:creator>
      <pubDate>Mon, 24 Aug 2026 10:12:35 +0000</pubDate>
      <link>https://dev.to/chriscornell/how-to-record-and-save-tiktok-live-streams-freetiktok-pio</link>
      <guid>https://dev.to/chriscornell/how-to-record-and-save-tiktok-live-streams-freetiktok-pio</guid>
      <description>&lt;p&gt;TikTok LIVE streams disappear once they end, so keeping a copy is often essential for reposting, analysis, or archiving. Here is a simple, free way to save any public TikTok LIVE as an original-quality MP4 - without keeping the app or a tab open.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;TikTok does not give you a usable download for live replays, and screen recording is unreliable (quality varies and it ties up your device).&lt;/p&gt;

&lt;h2&gt;
  
  
  The fix: a cloud recorder
&lt;/h2&gt;

&lt;p&gt;A cloud recorder captures the public live stream in the background and saves it as an original-quality MP4 you can download whenever you want. You can close the tab and it keeps recording.&lt;/p&gt;

&lt;h2&gt;
  
  
  A free option
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://tokliverecorder.com" rel="noopener noreferrer"&gt;TikTok Live Recorder&lt;/a&gt; records any public TikTok LIVE in the cloud and saves it as an original-quality MP4 - free, works in the browser, no install. The desktop version also supports 24/7 automatic recording for Twitch, YouTube, and Kick streams, which is great for creators or marketers who do not want to miss anything.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep it legal
&lt;/h2&gt;

&lt;p&gt;Only record streams you own or have permission to keep.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
