<?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: Shivam Agrawal</title>
    <description>The latest articles on DEV Community by Shivam Agrawal (@shivamagrawal).</description>
    <link>https://dev.to/shivamagrawal</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%2F4232239%2F419caa63-eac4-4a00-8153-fdf4734cd7c6.png</url>
      <title>DEV Community: Shivam Agrawal</title>
      <link>https://dev.to/shivamagrawal</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/shivamagrawal"/>
    <language>en</language>
    <item>
      <title>YouTube Broke 200,000 GitHub Stars: Why yt-dlp Now Needs an Entire JavaScript Engine Just to Save a Video</title>
      <dc:creator>Shivam Agrawal</dc:creator>
      <pubDate>Sat, 07 Nov 2026 18:02:51 +0000</pubDate>
      <link>https://dev.to/shivamagrawal/youtube-broke-200000-github-stars-why-yt-dlp-now-needs-an-entire-javascript-engine-just-to-save-a-4do4</link>
      <guid>https://dev.to/shivamagrawal/youtube-broke-200000-github-stars-why-yt-dlp-now-needs-an-entire-javascript-engine-just-to-save-a-4do4</guid>
      <description>&lt;p&gt;To save a YouTube video in 2026, &lt;a href="https://github.com/yt-dlp/yt-dlp" rel="noopener noreferrer"&gt;yt-dlp&lt;/a&gt;, a video downloader with over 200,000 stars on GitHub, has to start a whole separate JavaScript engine on your computer. Without one, its YouTube support is officially "deprecated." The engine it picked as the safe default is Deno, and last month Deno's makers &lt;a href="https://deno.com/blog/cloudflare" rel="noopener noreferrer"&gt;announced&lt;/a&gt; that they're joining Cloudflare and will stop developing the runtime after one more year. Another option, Bun, got frozen at its last pre-rewrite version in May because yt-dlp's maintainers think it has gone "fully vibe-coded."&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/yt-dlp" rel="noopener noreferrer"&gt;
        yt-dlp
      &lt;/a&gt; / &lt;a href="https://github.com/yt-dlp/yt-dlp" rel="noopener noreferrer"&gt;
        yt-dlp
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A feature-rich command-line audio/video downloader
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div&gt;
&lt;p&gt;&lt;a href="https://github.com/yt-dlp/yt-dlp#readme" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fyt-dlp%2Fyt-dlp%2Fmaster%2F.github%2Fbanner.svg" alt="YT-DLP"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/yt-dlp/yt-dlp#installation" title="Installation" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/7177b0ecf7b080fee2f95601ec32ce65206b7b655f03214de745f48d82c37422/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f79742d646c702f79742d646c703f636f6c6f723d627269676874677265656e266c6162656c3d4c6174657374267374796c653d666f722d7468652d6261646765" alt="Release version"&gt;&lt;/a&gt;
&lt;a href="https://github.com/yt-dlp/yt-dlp/blob/master/pyproject.toml" title="Python Version" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/24fc1d0f32b1255aedc43c8d6651b3907928d9651603ccd5241480bd08670d06/68747470733a2f2f696d672e736869656c64732e696f2f707974686f6e2f72657175697265642d76657273696f6e2d746f6d6c3f746f6d6c46696c65506174683d68747470732533412532462532467261772e67697468756275736572636f6e74656e742e636f6d25324679742d646c7025324679742d646c702532467265667325324668656164732532466d6173746572253246707970726f6a6563742e746f6d6c267374796c653d666f722d7468652d6261646765" alt="Python Version"&gt;&lt;/a&gt;
&lt;a href="https://pypi.org/project/yt-dlp" title="PyPI" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/f6b0ddaa5b40b858c5067e96040eb7f299fca7572e99cb10f870581079c80596/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d507950492d626c75652e7376673f6c6f676f3d70797069266c6162656c436f6c6f723d353535353535267374796c653d666f722d7468652d6261646765" alt="PyPI"&gt;&lt;/a&gt;
&lt;a href="https://discord.gg/H5MNcFW63r" title="Discord" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/8637d119ce330839c4b3fb76d8ba6de4e4428c43ae2592b90c53e375dcbd25e5/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f446973636f72642d2532333538363546322e7376673f266c6f676f3d646973636f7264266c6f676f436f6c6f723d7768697465267374796c653d666f722d7468652d6261646765" alt="Discord"&gt;&lt;/a&gt;
&lt;a href="https://github.com/yt-dlp/yt-dlp/LICENSE" title="License" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/3a55b40d1c445ba27494008636b1a06ecac5e78c9cb911266d17c665a3a1b354/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d556e6c6963656e73652d7265642e7376673f7374796c653d666f722d7468652d6261646765" alt="License: Unlicense"&gt;&lt;/a&gt;
&lt;a href="https://github.com/yt-dlp/yt-dlp/commits" title="Commit History" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/bf64ef305d01dd9f8700211e63c902869ae5c5ddeea73e12b71edd1a089bca67/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f636f6d6d69742d61637469766974792f6d2f79742d646c702f79742d646c703f6c6162656c3d636f6d6d697473267374796c653d666f722d7468652d6261646765" alt="Commits"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;yt-dlp is a feature-rich command-line audio/video downloader with support for &lt;a href="https://github.com/yt-dlp/yt-dlp/supportedsites.md" rel="noopener noreferrer"&gt;thousands of sites&lt;/a&gt;. The project is a fork of &lt;a href="https://github.com/ytdl-org/youtube-dl" rel="noopener noreferrer"&gt;youtube-dl&lt;/a&gt; based on the now inactive &lt;a href="https://github.com/blackjack4494/yt-dlc" rel="noopener noreferrer"&gt;youtube-dlc&lt;/a&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/yt-dlp/yt-dlp#installation" rel="noopener noreferrer"&gt;INSTALLATION&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/yt-dlp/yt-dlp/wiki/Installation" rel="noopener noreferrer"&gt;Detailed instructions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/yt-dlp/yt-dlp#release-files" rel="noopener noreferrer"&gt;Release Files&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/yt-dlp/yt-dlp#update" rel="noopener noreferrer"&gt;Update&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/yt-dlp/yt-dlp#dependencies" rel="noopener noreferrer"&gt;Dependencies&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/yt-dlp/yt-dlp#compile" rel="noopener noreferrer"&gt;Compile&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/yt-dlp/yt-dlp#usage-and-options" rel="noopener noreferrer"&gt;USAGE AND OPTIONS&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/yt-dlp/yt-dlp#general-options" rel="noopener noreferrer"&gt;General Options&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/yt-dlp/yt-dlp#network-options" rel="noopener noreferrer"&gt;Network Options&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/yt-dlp/yt-dlp#geo-restriction" rel="noopener noreferrer"&gt;Geo-restriction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/yt-dlp/yt-dlp#video-selection" rel="noopener noreferrer"&gt;Video Selection&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/yt-dlp/yt-dlp#download-options" rel="noopener noreferrer"&gt;Download Options&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/yt-dlp/yt-dlp#filesystem-options" rel="noopener noreferrer"&gt;Filesystem Options&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/yt-dlp/yt-dlp#thumbnail-options" rel="noopener noreferrer"&gt;Thumbnail Options&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/yt-dlp/yt-dlp#internet-shortcut-options" rel="noopener noreferrer"&gt;Internet Shortcut Options&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/yt-dlp/yt-dlp#verbosity-and-simulation-options" rel="noopener noreferrer"&gt;Verbosity and Simulation Options&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/yt-dlp/yt-dlp#workarounds" rel="noopener noreferrer"&gt;Workarounds&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/yt-dlp/yt-dlp#video-format-options" rel="noopener noreferrer"&gt;Video Format Options&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/yt-dlp/yt-dlp#subtitle-options" rel="noopener noreferrer"&gt;Subtitle Options&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/yt-dlp/yt-dlp#authentication-options" rel="noopener noreferrer"&gt;Authentication Options&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/yt-dlp/yt-dlp#post-processing-options" rel="noopener noreferrer"&gt;Post-processing Options&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/yt-dlp/yt-dlp#sponsorblock-options" rel="noopener noreferrer"&gt;SponsorBlock Options&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/yt-dlp/yt-dlp#extractor-options" rel="noopener noreferrer"&gt;Extractor Options&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/yt-dlp/yt-dlp#preset-aliases" rel="noopener noreferrer"&gt;Preset Aliases&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/yt-dlp/yt-dlp#configuration" rel="noopener noreferrer"&gt;CONFIGURATION&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/yt-dlp/yt-dlp#configuration-file-encoding" rel="noopener noreferrer"&gt;Configuration file encoding&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/yt-dlp/yt-dlp#authentication-with-netrc" rel="noopener noreferrer"&gt;Authentication with netrc&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/yt-dlp/yt-dlp#notes-about-environment-variables" rel="noopener noreferrer"&gt;Notes about environment variables&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/yt-dlp/yt-dlp#output-template" rel="noopener noreferrer"&gt;OUTPUT TEMPLATE&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/yt-dlp/yt-dlp#output-template-examples" rel="noopener noreferrer"&gt;Output template examples&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/yt-dlp/yt-dlp#format-selection" rel="noopener noreferrer"&gt;FORMAT SELECTION&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/yt-dlp/yt-dlp#filtering-formats" rel="noopener noreferrer"&gt;Filtering Formats&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/yt-dlp/yt-dlp#sorting-formats" rel="noopener noreferrer"&gt;Sorting Formats&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/yt-dlp/yt-dlp#format-selection-examples" rel="noopener noreferrer"&gt;Format Selection examples&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/yt-dlp/yt-dlp#modifying-metadata" rel="noopener noreferrer"&gt;MODIFYING METADATA&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/yt-dlp/yt-dlp#modifying-metadata-examples" rel="noopener noreferrer"&gt;Modifying metadata examples&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/yt-dlp/yt-dlp#extractor-arguments" rel="noopener noreferrer"&gt;EXTRACTOR ARGUMENTS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/yt-dlp/yt-dlp#plugins" rel="noopener noreferrer"&gt;PLUGINS&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/yt-dlp/yt-dlp#installing-plugins" rel="noopener noreferrer"&gt;Installing Plugins&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/yt-dlp/yt-dlp#developing-plugins" rel="noopener noreferrer"&gt;Developing Plugins&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/yt-dlp/yt-dlp#embedding-yt-dlp" rel="noopener noreferrer"&gt;EMBEDDING YT-DLP&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/yt-dlp/yt-dlp#embedding-examples" rel="noopener noreferrer"&gt;Embedding examples&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/yt-dlp/yt-dlp#changes-from-youtube-dl" rel="noopener noreferrer"&gt;CHANGES FROM YOUTUBE-DL&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/yt-dlp/yt-dlp#new-features" rel="noopener noreferrer"&gt;New features&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/yt-dlp/yt-dlp#differences-in-default-behavior" rel="noopener noreferrer"&gt;Differences in default behavior&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/yt-dlp/yt-dlp#deprecated-options" rel="noopener noreferrer"&gt;Deprecated options&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/yt-dlp/yt-dlp/CONTRIBUTING.md#contributing-to-yt-dlp" rel="noopener noreferrer"&gt;CONTRIBUTING&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/yt-dlp/yt-dlp/CONTRIBUTING.md#opening-an-issue" rel="noopener noreferrer"&gt;Opening an Issue&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/yt-dlp/yt-dlp/CONTRIBUTING.md#developer-instructions" rel="noopener noreferrer"&gt;Developer Instructions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/yt-dlp/yt-dlp/wiki" rel="noopener noreferrer"&gt;WIKI&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/yt-dlp/yt-dlp/wiki/FAQ" rel="noopener noreferrer"&gt;FAQ&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;INSTALLATION&lt;/h1&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp.exe" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/8848c7876398d9a6bf174558735641ad7cc2d10a0e018f2cb4826baceb344e33/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d57696e646f77735f7836342d626c75652e7376673f7374796c653d666f722d7468652d6261646765266c6f676f3d77696e646f7773" alt="Windows"&gt;&lt;/a&gt;
&lt;a href="https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/31d5c6ac526e54664a7fb2c7957efc97fa943fd94d1e9d41fe9cc1a94c3e6537/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d4c696e75782f4253442d7265642e7376673f7374796c653d666f722d7468652d6261646765266c6f676f3d6c696e7578" alt="Unix"&gt;&lt;/a&gt;
&lt;a href="https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp_macos" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/7945f7581dd6def4f9939c277b2434cc74671d5ec930a2628e8027f96562b622/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d4d61634f532d6c69676874626c75652e7376673f7374796c653d666f722d7468652d6261646765266c6f676f3d6170706c65" alt="MacOS"&gt;&lt;/a&gt;
&lt;a href="https://pypi.org/project/yt-dlp" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/f6b0ddaa5b40b858c5067e96040eb7f299fca7572e99cb10f870581079c80596/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d507950492d626c75652e7376673f6c6f676f3d70797069266c6162656c436f6c6f723d353535353535267374796c653d666f722d7468652d6261646765" alt="PyPI"&gt;&lt;/a&gt;
&lt;a href="https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp.tar.gz" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/2ed3c5c3ab1a1d8861980f1fcf497f651453e36ae9e269cf6fb599e380a41ac8/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d536f757263655f7461722d677265656e2e7376673f7374796c653d666f722d7468652d6261646765" alt="Source Tarball"&gt;&lt;/a&gt;
&lt;a href="https://github.com/yt-dlp/yt-dlp#release-files" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/36345c7e6ac946b9275e4eb94090cbcd727a7308c578b933facffc27383d9dc1/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d4f746865722d677265792e7376673f7374796c653d666f722d7468652d6261646765" alt="Other variants"&gt;&lt;/a&gt;
&lt;a href="https://github.com/yt-dlp/yt-dlp/releases" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/fc26f6cc079065176a5c0cd5b68ecc58205d38466c521da7fc54601806f969de/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d416c6c5f56657273696f6e732d6c69676874677265792e7376673f7374796c653d666f722d7468652d6261646765" alt="All versions"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can install yt-dlp using &lt;a href="https://github.com/yt-dlp/yt-dlp#release-files" rel="noopener noreferrer"&gt;the binaries&lt;/a&gt;, &lt;a href="https://pypi.org/project/yt-dlp" rel="nofollow noopener noreferrer"&gt;pip&lt;/a&gt; or one using a third-party…&lt;/p&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/yt-dlp/yt-dlp" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;I haven't run any of this. I read yt-dlp's source and its issue tracker instead, and the code tells the story better than the announcements do.&lt;/p&gt;

&lt;h2&gt;
  
  
  The record labels went after this exact trick
&lt;/h2&gt;

&lt;p&gt;In 2020 the RIAA sent GitHub a &lt;a href="https://github.com/github/dmca/blob/master/2020/10/2020-10-23-RIAA.md" rel="noopener noreferrer"&gt;takedown notice&lt;/a&gt; against youtube-dl, yt-dlp's parent project. Its complaint was specific. The code, it said, gets around YouTube's "rolling cipher," and the project's own sample downloads included Taylor Swift's "Shake It Off." GitHub pulled the repo, then &lt;a href="https://github.blog/news-insights/policy-news-and-insights/standing-up-for-developers-youtube-dl-is-back/" rel="noopener noreferrer"&gt;put it back&lt;/a&gt; a few weeks later.&lt;/p&gt;

&lt;p&gt;The yt-dlp repo went up three days after that notice. Today it has over 60,000 more stars than youtube-dl, which hasn't tagged a release since 2021, and it inherited the same problem the lawyers had put their finger on.&lt;/p&gt;

&lt;p&gt;Remember that phrase, rolling cipher. It's still the whole fight.&lt;/p&gt;

&lt;h2&gt;
  
  
  For years it faked JavaScript in Python
&lt;/h2&gt;

&lt;p&gt;Here's the cipher in plain terms. When you press play, YouTube's player script scrambles a couple of values in the video's URL: a signature, and a parameter the community calls &lt;code&gt;n&lt;/code&gt;. Ask for the stream without doing that scrambling yourself and you get &lt;a href="https://github.com/ytdl-org/youtube-dl/issues/29326" rel="noopener noreferrer"&gt;throttled&lt;/a&gt; to a crawl, or an HTTP 403. So any downloader has to run YouTube's own JavaScript, and there's no shortcut, because the scrambling code is rewritten and re-obfuscated every time Google ships a new version of its player.&lt;/p&gt;

&lt;p&gt;yt-dlp is a Python program. Its answer, for years, was to write a JavaScript interpreter in Python, almost a thousand lines of it. The heart of it is a table that maps JavaScript operators onto Python ones:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;_OPERATORS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  &lt;span class="c1"&gt;# None =&amp;gt; Defined in JSInterpreter._operator
&lt;/span&gt;    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;?&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;??&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;|&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;_js_bit_op&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;operator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;or_&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;===&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;operator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;==&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;_js_eq_op&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;operator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;_js_bit_op&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;operator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rshift&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;+&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;_js_arith_op&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;operator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;%&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;_js_mod&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;**&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;_js_exp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;# …
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every bitwise operation goes through a helper that squeezes Python's unlimited integers back into JavaScript's signed 32 bits. It's a careful little imitation of a whole programming language, built by volunteers for one purpose: running a single obfuscated function that Google's engineers keep rewriting. One Hacker News commenter &lt;a href="https://news.ycombinator.com/item?id=45359630" rel="noopener noreferrer"&gt;called it&lt;/a&gt; "a brilliant hack but limited in capability."&lt;/p&gt;

&lt;p&gt;Limited is putting it kindly.&lt;/p&gt;

&lt;p&gt;The maintainers had to find YouTube's functions with regex before they could interpret them. In the &lt;a href="https://github.com/yt-dlp/yt-dlp/issues/14404" rel="noopener noreferrer"&gt;announcement&lt;/a&gt; that ended this approach, maintainer &lt;a href="https://github.com/bashonly" rel="noopener noreferrer"&gt;bashonly&lt;/a&gt; described what every player change cost them:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Any time YouTube changed something about their player JS, it would cause multiple maintainers to drop everything and spend all of their free time for the next 2-3 days trying to fix things.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Then YouTube spread those functions all over the player, and the same post estimates the old method would now eat "2-3 &lt;em&gt;weeks&lt;/em&gt;" of maintainers' free time per breakage. So last year yt-dlp gave up and started handing the job to a real JavaScript runtime, with a solver kept in a &lt;a href="https://github.com/yt-dlp/ejs" rel="noopener noreferrer"&gt;separate repo&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The engine it trusted is about to lose its developers
&lt;/h2&gt;

&lt;p&gt;Why not just use Node, you might ask?&lt;/p&gt;

&lt;p&gt;Safety. The solver executes code fetched from Google's servers, on the machines of what the maintainers call their "less-technically-inclined users." Deno blocks file and network access by default. You can see the paranoia in the provider code, which starts Deno with &lt;code&gt;--no-remote&lt;/code&gt;, &lt;code&gt;--no-prompt&lt;/code&gt; and &lt;code&gt;--no-config&lt;/code&gt; and feeds it the script through standard input. Deno is the only runtime switched on by default; Node, Bun and QuickJS stay off unless you pass a flag to opt in yourself.&lt;/p&gt;

&lt;p&gt;Then, last month, Deno's makers announced they were joining Cloudflare:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We will support the Deno runtime for another year with monthly releases containing bug fixes and security updates. After that year we will end our development of the Deno runtime.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A user opened &lt;a href="https://github.com/yt-dlp/yt-dlp/issues/17799" rel="noopener noreferrer"&gt;an issue&lt;/a&gt; the same day asking yt-dlp to plan for a new default. It's still open. Node isn't an easy swap: in that thread, one participant &lt;a href="https://github.com/yt-dlp/yt-dlp/issues/17799" rel="noopener noreferrer"&gt;argues&lt;/a&gt; its permission sandbox is "still not hardened enough."&lt;/p&gt;

&lt;p&gt;Bun is worse off. In May the maintainers &lt;a href="https://github.com/yt-dlp/yt-dlp/issues/16766" rel="noopener noreferrer"&gt;capped it&lt;/a&gt;, and the reason is the most-reacted issue in the repo's history:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Bun was recently rewritten in Rust using Claude, and its development seems to have taken a turn towards being fully vibe-coded.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;They meant it. The Bun provider hard-codes version 1.3.14 as "the last supported bun version" and refuses to run anything newer.&lt;/p&gt;

&lt;h2&gt;
  
  
  What changes for you
&lt;/h2&gt;

&lt;p&gt;If you've ever pasted a link into yt-dlp and gotten a &lt;a href="https://github.com/yt-dlp/yt-dlp/issues/17456" rel="noopener noreferrer"&gt;403&lt;/a&gt;, this fight is usually somewhere behind it. The official binaries bundle the solver. If you installed with pip, you need the &lt;code&gt;yt-dlp[default]&lt;/code&gt; extra plus Deno somewhere on your PATH, and if you got it from Homebrew or a Linux package manager, it depends on how your packager decided to split things up. Skip the runtime and the maintainers &lt;a href="https://github.com/yt-dlp/yt-dlp/issues/15012" rel="noopener noreferrer"&gt;say plainly&lt;/a&gt; that your YouTube formats will keep shrinking, and that this "will not be considered a 'bug' but rather an inevitability."&lt;/p&gt;

&lt;p&gt;The other sites are fine.&lt;/p&gt;

&lt;p&gt;yt-dlp ships more than 1,700 extractors, and almost none of them need JavaScript. This is a YouTube problem. It's also the problem that keeps landing on Hacker News, where three threads about it have each pulled in more than 600 comments.&lt;/p&gt;

&lt;h2&gt;
  
  
  The real threat isn't Google
&lt;/h2&gt;

&lt;p&gt;Think about where that leaves a Python project with a public-domain license and a strict no-AI contribution policy. Its YouTube support now rests on runtimes it doesn't control, and of the five it supports, one is losing its developers, one is frozen at an old version, and the obvious replacement fails the same safety test that picked Deno in the first place.&lt;/p&gt;

&lt;p&gt;That's not a long list.&lt;/p&gt;

&lt;p&gt;The maintainers once wrote that switching to a headless browser "would be an admission of defeat." Years of YouTube changes never got them there.&lt;/p&gt;

&lt;p&gt;The JavaScript ecosystem might do it in one.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>python</category>
      <category>javascript</category>
      <category>discuss</category>
    </item>
    <item>
      <title>AI Can Write a Good Story Now. It Can't Write the Second One.</title>
      <dc:creator>Shivam Agrawal</dc:creator>
      <pubDate>Sat, 07 Nov 2026 17:46:39 +0000</pubDate>
      <link>https://dev.to/shivamagrawal/ai-can-write-a-good-story-now-it-cant-write-the-second-one-34h1</link>
      <guid>https://dev.to/shivamagrawal/ai-can-write-a-good-story-now-it-cant-write-the-second-one-34h1</guid>
      <description>&lt;p&gt;&lt;em&gt;Machine-written fiction is winning blind tests. Readers still mark it down the moment they know. Both facts point at the same thing.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;In August, researchers at Villanova University published an experiment with 1,682 readers in the journal &lt;em&gt;Judgment and Decision Making&lt;/em&gt;. Readers were given short stories, three by published human authors and three by ChatGPT, and half the time the researchers lied about who wrote which. The AI stories were rated higher on quality and on how absorbing they were. The highest scores of all went to AI stories falsely labeled as human.&lt;/p&gt;

&lt;p&gt;So the machines win. Except the same study found an equally strong pull the other way. Whatever readers were told was written by a person got higher marks, no matter who actually wrote it. When asked to guess the true author, readers did no better than a coin flip.&lt;/p&gt;

&lt;p&gt;I think that contradiction is the whole story of storytelling right now. The argument over whether AI can write a good story is mostly settled: for short fiction and a general readership, it can. What it struggles with is something we never had to name, because we never ran short of it. Difference. And when readers mark down a story labeled "AI," they aren't reacting to the sentences. They're reacting to the empty chair where the author should be.&lt;/p&gt;

&lt;h2&gt;
  
  
  Text used to be a receipt
&lt;/h2&gt;

&lt;p&gt;For most of history, a well-made story proved something. You couldn't get a coherent, emotionally pitched 3,000 words without a person spending days on them, so the text worked as a receipt: someone sat down, picked these words, and meant them. Nobody had to think about authorship separately from quality, because one implied the other.&lt;/p&gt;

&lt;p&gt;That link broke within three months of ChatGPT's release. &lt;em&gt;Clarkesworld&lt;/em&gt;, a science-fiction magazine that pays writers for short stories and had shut its doors in the previous ten years only for software or server updates, closed submissions on February 20, 2023. By noon that day, editor Neil Clarke had counted 500 machine-written submissions against 700 legitimate ones. The stories weren't good. They didn't need to be. They cost nothing to produce, and so the receipt stopped meaning anything.&lt;/p&gt;

&lt;p&gt;Once text stops proving effort, readers start asking a question they rarely asked before: who is this from? Most of the confusion about AI and storytelling comes from treating that as a question about quality.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the AI stories win
&lt;/h2&gt;

&lt;p&gt;It's worth being honest about why machine stories score well, because the reason flatters nobody.&lt;/p&gt;

&lt;p&gt;The Villanova authors suggested readers preferred the AI stories because they were more direct and easier to follow. The AI versions usually stated their themes outright instead of leaving them for the reader to work out. With a reader who is skimming, that's a real advantage. Most readers are skimming.&lt;/p&gt;

&lt;p&gt;In 2025 the fantasy novelist Mark Lawrence posted a blind test on his blog, asking readers to judge flash fiction from humans and from AI. The top-voted story was AI-written. The writer Ozy Brennan read the entries and drew a harsher lesson: "wow, humans are &lt;em&gt;garbage&lt;/em&gt; at both writing and reading flash fiction." The AI didn't clear a high bar. The bar was on the floor, and the AI stepped over it every time, which is more than most of the humans managed.&lt;/p&gt;

&lt;p&gt;Ted Chiang described the mechanism in his 2024 &lt;em&gt;New Yorker&lt;/em&gt; essay "Why A.I. Isn't Going to Make Art." A ten-thousand-word story, he wrote, requires something on the order of ten thousand choices. A hundred-word prompt supplies about a hundred. The model has to fill in everything else, and one way it does that is to "take an average of the choices that other writers have made," which Chiang calls "the least interesting choices possible."&lt;/p&gt;

&lt;p&gt;The least interesting choice is often a perfectly good one. Clear theme. Clean arc. An ending that lands where you expected it to, delivered in sentences that never trip you. Averages are pleasant, and that's exactly why they test well one at a time.&lt;/p&gt;

&lt;h2&gt;
  
  
  The second-story problem
&lt;/h2&gt;

&lt;p&gt;The trouble only shows up in aggregate.&lt;/p&gt;

&lt;p&gt;In 2024, Anil Doshi of UCL and Oliver Hauser of the University of Exeter published a study in &lt;em&gt;Science Advances&lt;/em&gt;. About 300 people wrote eight-sentence stories, some with ideas from GPT-4 and some without, and 600 more people judged them. The AI help worked. Writers who could see AI ideas produced stories rated 8.1% more novel and 9% more useful, and the least creative writers gained the most: their stories came out up to 26.6% better written and 15.2% less boring. But stories from writers who used even one AI idea were 10.7% more similar to each other than stories from writers who used none.&lt;/p&gt;

&lt;p&gt;Doshi and Hauser framed it as a social dilemma. Each writer is better off using the tool, while the pool of stories, taken together, gets narrower.&lt;/p&gt;

&lt;p&gt;A 2026 paper from the University of Hamburg, "Do Large Language Models Always Tell The Same Stories?", measured that narrowing head-on. Thennal D K and Hans Ole Hatzel took prompts from Reddit's r/WritingPrompts, had ten models write stories for them, and asked judges which of two stories was narratively closer to a reference. Two human stories written for the same prompt were picked as the closer pair about 30% of the time, while for two stories from the same model the figure sat between 80% and 90%. Frontier models, the authors write, "converge on a 'mean' generic narrative." Raising the temperature or telling the model to avoid its earlier ideas didn't meaningfully help.&lt;/p&gt;

&lt;p&gt;So the machine writes a good first story. Ask for a second and you get the first one in a different hat.&lt;/p&gt;

&lt;p&gt;That matters more than it sounds, because nobody reads one story. A culture is a set of stories, and what makes the set worth having is that its members disagree with each other about what happens next. If every bedtime story, brand film, and short-fiction contest entry starts from the same average, each one can be individually fine while the whole shelf turns beige.&lt;/p&gt;

&lt;h2&gt;
  
  
  The penalty isn't snobbery
&lt;/h2&gt;

&lt;p&gt;Back to the readers who mark down anything labeled AI.&lt;/p&gt;

&lt;p&gt;The largest study on this, by Manav Raj, Justin Berg, and Rob Seamans, appeared in 2025 in the &lt;em&gt;Journal of Experimental Psychology: General&lt;/em&gt;. Across 16 experiments and 27,491 participants, the text stayed the same and only the label changed, and readers consistently rated writing lower on quality, creativity, and enjoyment when told AI produced it. Raj calls this the "AI disclosure discount." The researchers tried to make it go away by changing genre, tone, and character type, by describing the AI's impressive abilities, even by giving it a name and gender. None of it reliably worked. Telling readers that a person had used AI as a tool didn't help either; that version was judged as harshly as the machine alone. The factor that best explained the drop was perceived authenticity.&lt;/p&gt;

&lt;p&gt;You can call this bias, and in a narrow sense it is: identical words, different scores. I'm not convinced it's irrational, though. Chiang gives the clearest account of why. Language, he argues, "requires an intention to communicate." When someone says "I'm sorry" to you, it doesn't matter that the words are unoriginal, because what you're receiving is that this person meant them, now, to you. Stories work the same way. Part of what you read is a message from someone in particular, shaped by a life you don't share.&lt;/p&gt;

&lt;p&gt;Take away the sender and you still have a pleasant text. You no longer have a message. Readers can't detect the difference, as the Villanova coin-flip result shows, but they clearly care about it, which is why the label moves the score so much. The label is the only evidence they've got.&lt;/p&gt;

&lt;h2&gt;
  
  
  The strongest objection
&lt;/h2&gt;

&lt;p&gt;There's a real counterargument here, and it isn't settled.&lt;/p&gt;

&lt;p&gt;A study described in &lt;em&gt;The Conversation&lt;/em&gt; in March 2025 gave more than 650 people a story that ChatGPT-4o wrote in the style of the author Jason Brown. Readers told it was AI rated it lower on authenticity and evocativeness, and almost 40% said they would have paid less for AI-written content. Then the researchers looked at behavior, and it didn't move: readers spent the same time on the story and were willing to give up the same money to finish it, whatever label they saw.&lt;/p&gt;

&lt;p&gt;Maybe, then, the authenticity penalty is something people say rather than something they do. If so, the economics are brutal. Readers tell surveys they want human stories and then consume whatever is cheapest and most absorbing, and the AI story is both. The &lt;em&gt;Clarkesworld&lt;/em&gt; flood suggests supply won't be the constraint.&lt;/p&gt;

&lt;p&gt;I don't know which way this breaks. What I'd point out is that the behavior study measured one story, and the sameness problem only shows up across many. A reader can happily finish one averaged story. Whether they'll keep returning to a feed where every story converges on the same shape is a different question, and nobody has run that experiment yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's scarce now
&lt;/h2&gt;

&lt;p&gt;If you tell stories for a living, or just to raise money, sell a product, or keep a newsletter alive, the practical consequence is fairly plain. The competent, clear, anonymous story now costs nothing; it was never really the hard part, but it used to be expensive enough to look like the hard part.&lt;/p&gt;

&lt;p&gt;What's left is whatever can't be averaged: the detail only you noticed, the choice a model wouldn't make because almost nobody in its training data made it, and your name standing behind the result. Chiang's phrase for this is "the fact that you're the one who is saying it." A few years ago that would have read as sentiment. Now it reads more like a spec.&lt;/p&gt;

&lt;p&gt;Underneath all of this sits an uncomfortable loop. Every model writes the average of the stories people wrote before it. If more of the stories people write now start from that average, the next model's average gets flatter, and the one after that flatter still. Ed Finn, founding director of Arizona State University's Center for Science and the Imagination, put the risk bluntly on the podcast &lt;em&gt;Generation AI&lt;/em&gt;: "We're sort of eating the seed corn right now."&lt;/p&gt;

&lt;p&gt;Whether AI can tell a good story was the easy question. The harder one is who keeps writing the strange stories it learns from, and whether anyone will pay them to.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>writing</category>
      <category>discuss</category>
      <category>technology</category>
    </item>
  </channel>
</rss>
