<?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>Forem: Joseph Harrison</title>
    <description>The latest articles on Forem by Joseph Harrison (@joseph_harrison_3e22b55af).</description>
    <link>https://forem.com/joseph_harrison_3e22b55af</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3587374%2Fdac2cc1c-a25d-401c-b12d-7cc9b1569115.png</url>
      <title>Forem: Joseph Harrison</title>
      <link>https://forem.com/joseph_harrison_3e22b55af</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/joseph_harrison_3e22b55af"/>
    <language>en</language>
    <item>
      <title>Advanced YouTube to mp4 Converter.</title>
      <dc:creator>Joseph Harrison</dc:creator>
      <pubDate>Wed, 29 Oct 2025 12:40:26 +0000</pubDate>
      <link>https://forem.com/joseph_harrison_3e22b55af/advanced-youtube-to-mp4-converter-3kg5</link>
      <guid>https://forem.com/joseph_harrison_3e22b55af/advanced-youtube-to-mp4-converter-3kg5</guid>
      <description>&lt;p&gt;How the “YouTube to MP4” App Works&lt;br&gt;
A technical deep dive into the pipeline, components, and packaging&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;High-level overview&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The &lt;code&gt;YouTube to mp4.exe&lt;/code&gt; app is a self-contained Windows program that takes a YouTube URL and produces an &lt;code&gt;.mp4&lt;/code&gt; file on disk. Behind the scenes it’s a Python application wrapped into a standalone &lt;code&gt;.exe&lt;/code&gt;. The main building blocks are:&lt;/p&gt;

&lt;p&gt;1) GUI layer: A resizable desktop interface built with &lt;code&gt;customtkinter&lt;/code&gt; (a themed version of Tkinter).&lt;br&gt;
2) Download core: &lt;code&gt;yt_dlp&lt;/code&gt;, an advanced YouTube/media downloader library.&lt;br&gt;
3) Transcode / merge layer: &lt;code&gt;ffmpeg&lt;/code&gt;, a command-line multimedia tool used to stitch audio and video into one MP4.&lt;br&gt;
4) Packaging layer: A PyInstaller / auto-py-to-exe bundle that ships Python, &lt;code&gt;yt_dlp&lt;/code&gt;, and &lt;code&gt;ffmpeg&lt;/code&gt; in one file so it runs on a Windows machine without needing Python installed.&lt;/p&gt;

&lt;p&gt;The flow looks like this:&lt;/p&gt;

&lt;p&gt;[User pastes URL + picks quality/bitrate in GUI]&lt;br&gt;
                |&lt;br&gt;
                v&lt;br&gt;
        [yt_dlp probes YouTube]&lt;br&gt;
                |&lt;br&gt;
                v&lt;br&gt;
   [App picks the right video stream +&lt;br&gt;
          best matching audio]&lt;br&gt;
                |&lt;br&gt;
                v&lt;br&gt;
   [Download video-only + audio-only]&lt;br&gt;
                |&lt;br&gt;
                v&lt;br&gt;
        [ffmpeg merges them]&lt;br&gt;
                |&lt;br&gt;
                v&lt;br&gt;
          [Final MP4 saved]&lt;/p&gt;

&lt;p&gt;At very low resolutions (like 360p), YouTube often provides “progressive” MP4s that already contain both audio and video in one file. In that case the pipeline is shorter: no merge step is needed. At higher qualities (720p, 1080p, 1440p, 2160p/4K), YouTube usually splits audio and video into separate tracks, so you have to download both and mux them together.&lt;/p&gt;

&lt;p&gt;The app automates all of that so the user just clicks Download.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The GUI layer (CustomTkinter)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Tech used&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;tkinter&lt;/code&gt; is Python’s standard library GUI toolkit.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;customtkinter&lt;/code&gt; is an enhanced theming layer on top of tkinter that gives you modern-looking widgets, dark mode styling, sliders, switches, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;From inspecting the bundled executable, we can see &lt;code&gt;customtkinter&lt;/code&gt; modules (&lt;code&gt;customtkinter.windows.widgets.ctk_button&lt;/code&gt;, &lt;code&gt;ctk_slider&lt;/code&gt;, &lt;code&gt;ctk_label&lt;/code&gt;, etc.) embedded in the binary. That tells us the interface isn’t just bare Tkinter — it’s using CustomTkinter widgets for cleaner layout and nicer visuals.&lt;/p&gt;

&lt;p&gt;What the interface does&lt;br&gt;
The GUI typically provides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A text field to paste the YouTube URL.&lt;/li&gt;
&lt;li&gt;Controls to choose output quality (e.g. 360p → 4K).&lt;/li&gt;
&lt;li&gt;A bitrate / quality slider for video.&lt;/li&gt;
&lt;li&gt;Toggle-style options (for example: “video+audio MP4” vs “audio-only MP3/M4A”, or similar optional features).&lt;/li&gt;
&lt;li&gt;A start/download button.&lt;/li&gt;
&lt;li&gt;A progress area or status label to show what’s happening.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There was also work done so the window is resizable, because long labels / switches on the far right were getting cut off in earlier fixed-size versions. You can see evidence of that in an internal string:&lt;br&gt;
&lt;code&gt;YouTube_yt_dlp_GUI_v2_resizable&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;So “v2_resizable” is basically UX polish:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The window can stretch horizontally.&lt;/li&gt;
&lt;li&gt;Text on the far-right no longer gets clipped.&lt;/li&gt;
&lt;li&gt;Sliders and toggle switches stay visible.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Event flow&lt;br&gt;
When you click Download:&lt;/p&gt;

&lt;p&gt;1) The GUI grabs all the current settings (URL, chosen resolution/bitrate, etc.).&lt;br&gt;
2) It calls into the download function (a Python function in your app).&lt;br&gt;
3) While download/transcode is happening, the GUI can update the status text (“Downloading video…”, “Merging audio…”, etc.) instead of freezing silently.&lt;/p&gt;

&lt;p&gt;That last part usually uses either:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;after()&lt;/code&gt; callbacks in Tkinter to poll progress, or&lt;/li&gt;
&lt;li&gt;threading so the UI doesn’t lock while &lt;code&gt;yt_dlp&lt;/code&gt; and &lt;code&gt;ffmpeg&lt;/code&gt; are running.&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Format discovery (getting the available qualities)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When you paste a YouTube link, the app doesn’t just blindly download. Step one is “probe the video.”&lt;/p&gt;

&lt;p&gt;Under the hood this is &lt;code&gt;yt_dlp.YoutubeDL().extract_info(url, download=False)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That call:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Connects to YouTube.&lt;/li&gt;
&lt;li&gt;Collects metadata (title, duration, channel, etc.).&lt;/li&gt;
&lt;li&gt;Enumerates all available formats: every resolution, container type, codec, bitrate, whether it has audio, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result is basically a big Python dict. A simplified version of what one entry in &lt;code&gt;formats&lt;/code&gt; might look like:&lt;/p&gt;

&lt;p&gt;{&lt;br&gt;
    "format_id": "248",&lt;br&gt;
    "ext": "webm",&lt;br&gt;
    "vcodec": "vp9",&lt;br&gt;
    "acodec": "none",&lt;br&gt;
    "height": 1080,&lt;br&gt;
    "fps": 30,&lt;br&gt;
    "tbr": 2500.12,   # approx video bitrate in kbps&lt;br&gt;
    "filesize": 12345678,&lt;br&gt;
    "url": "&lt;a href="https://r3---sn-abc123.googlevideo.com/videoplayback?.." rel="noopener noreferrer"&gt;https://r3---sn-abc123.googlevideo.com/videoplayback?..&lt;/a&gt;."&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;Some formats are audio-only (&lt;code&gt;acodec&lt;/code&gt; is set, &lt;code&gt;vcodec&lt;/code&gt; is &lt;code&gt;none&lt;/code&gt;).&lt;br&gt;
Some are video-only (&lt;code&gt;vcodec&lt;/code&gt; is set, &lt;code&gt;acodec&lt;/code&gt; is &lt;code&gt;none&lt;/code&gt;).&lt;br&gt;
Some (usually ≤480p) are “progressive,” meaning they include both audio and video in one file.&lt;/p&gt;

&lt;p&gt;Your GUI uses this data to populate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The resolution dropdown / slider.&lt;/li&gt;
&lt;li&gt;The bitrate slider (because &lt;code&gt;tbr&lt;/code&gt; gives an approximate bitrate).&lt;/li&gt;
&lt;li&gt;Potentially which formats are even allowed. For example, if the user chooses 4K but the video only goes up to 1080p, the app can warn them or silently fall back.&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Choosing the right streams&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Once the user picks a target quality, the app applies selection logic. In English:&lt;/p&gt;

&lt;p&gt;1) If a progressive MP4 exists at or below the requested quality:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Grab that single file. Done.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;2) Else (adaptive streaming path):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Find the best video-only stream that matches the requested resolution or bitrate.&lt;/li&gt;
&lt;li&gt;Find the best audio-only stream (often &lt;code&gt;m4a&lt;/code&gt; or &lt;code&gt;opus&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Download both separately.&lt;/li&gt;
&lt;li&gt;Merge them into final MP4.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This two-track path is required for HD and above because YouTube serves HD/FullHD/4K as DASH/HLS adaptive segments: video and audio are delivered separately.&lt;/p&gt;

&lt;p&gt;Some versions of your app include a manual bitrate slider for video. That slider influences which &lt;code&gt;yt_dlp&lt;/code&gt; format is chosen. Instead of always taking “bestvideo”, it can pick the stream with a total bitrate closest to the slider value. That’s handy if you want smaller file sizes instead of always forcing the top-bitrate variant.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Downloading the streams&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;yt_dlp&lt;/code&gt; can either:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Be asked to download the formats directly to disk, or&lt;/li&gt;
&lt;li&gt;Be asked just to give you the direct media URLs, and then you download them yourself.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most YouTube download tools do something like:&lt;/p&gt;

&lt;p&gt;ydl_opts = {&lt;br&gt;
    "outtmpl": "C:/path/%(title)s.%(ext)s",&lt;br&gt;
    "format": "bestvideo[height&amp;lt;=1080]+bestaudio/best[height&amp;lt;=1080]",&lt;br&gt;
    "merge_output_format": "mp4",&lt;br&gt;
    "ffmpeg_location": "path\to\ffmpeg.exe"&lt;br&gt;
}&lt;br&gt;
with yt_dlp.YoutubeDL(ydl_opts) as ydl:&lt;br&gt;
    ydl.download([url])&lt;/p&gt;

&lt;p&gt;That &lt;code&gt;format&lt;/code&gt; string is powerful. It literally tells &lt;code&gt;yt_dlp&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Try to grab best video up to 1080p plus best audio.&lt;/li&gt;
&lt;li&gt;If that fails, fall back to best progressive format up to 1080p.&lt;/li&gt;
&lt;li&gt;Output as MP4 in the end.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In your app, this logic is effectively wrapped behind GUI choices instead of requiring the user to know the syntax. The GUI converts “1080p” + “target bitrate 4 Mbps” + “MP4 output” into actual yt_dlp options.&lt;/p&gt;

&lt;p&gt;While downloading, yt_dlp also produces progress hooks. The app can register a callback that receives events like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;“downloading: 34.5%”&lt;/li&gt;
&lt;li&gt;“postprocessing: merging formats”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s how the GUI can update a label or progress bar live.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Merging audio + video into MP4&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When the video-only and audio-only files are finished, we end up with something like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;temp_video.webm&lt;/code&gt; (VP9, H.264, etc.)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;temp_audio.m4a&lt;/code&gt; (AAC)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To turn those into one playable &lt;code&gt;.mp4&lt;/code&gt;, the app uses &lt;code&gt;ffmpeg&lt;/code&gt;. &lt;code&gt;ffmpeg&lt;/code&gt; is a command-line tool that can mux streams together, convert codecs, change containers, etc.&lt;/p&gt;

&lt;p&gt;A typical merge command (conceptually) looks like:&lt;/p&gt;

&lt;p&gt;ffmpeg -i temp_video.webm -i temp_audio.m4a ^&lt;br&gt;
  -c:v copy -c:a aac ^&lt;br&gt;
  "FinalVideo.mp4"&lt;/p&gt;

&lt;p&gt;Key points:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-c:v copy&lt;/code&gt; means “don’t re-encode the video, just copy the stream.” That preserves quality and speeds things up.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-c:a aac&lt;/code&gt; either copies AAC directly or re-encodes audio to AAC, depending on source format and MP4 compatibility.&lt;/li&gt;
&lt;li&gt;Output is a normal MP4 that basically every player can open.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In many GUI-driven downloaders, you never see this step because it’s done automatically. &lt;code&gt;yt_dlp&lt;/code&gt; can even call &lt;code&gt;ffmpeg&lt;/code&gt; for you as a “postprocessor,” so you don’t always have to shell out manually. The executable includes &lt;code&gt;yt_dlp.postprocessor.ffmpeg&lt;/code&gt;, so we know that ffmpeg postprocessing is built-in.&lt;/p&gt;

&lt;p&gt;In plain terms: the tool quietly runs ffmpeg behind the scenes to deliver a final MP4 that “just works.”&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Handling YouTube quirks (consent, age gates, etc.)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;YouTube sometimes walls off higher-quality or certain tracks behind extra checks (cookie consent, age verification, region restrictions, etc.).&lt;/p&gt;

&lt;p&gt;That’s why:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You might see low-res formats (like 360p) download fine,&lt;/li&gt;
&lt;li&gt;but 1080p / 4K fails with messages about consent or “sign in to confirm your age.”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The app tries to solve the “normal” path (public videos, no login). For restricted videos, two things can happen:&lt;br&gt;
1) yt_dlp throws an error saying it can’t fetch the high-res formats.&lt;br&gt;
2) The merge step never triggers because the high-res video-only stream never came down.&lt;/p&gt;

&lt;p&gt;There’s been discussion around importing cookies from Chrome / Opera GX so yt_dlp can pretend to be your logged-in browser. That’s a common workaround: passing a cookies file lets yt_dlp access formats your browser is allowed to see. The fact that browsers like Opera GX and Chrome were mentioned means the tool is being pushed in that direction, even if it’s not fully automated.&lt;/p&gt;

&lt;p&gt;In other words:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Low resolutions = easier, single file, no special access.&lt;/li&gt;
&lt;li&gt;High resolutions / HDR / age-restricted videos = may require browser cookies or fail if you’re “unauthenticated.”&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Output management&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After the merge, the app:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Builds a sane filename (usually based on the YouTube title, cleaned so it’s a valid Windows filename).&lt;/li&gt;
&lt;li&gt;Saves the final MP4 to a chosen folder (often Downloads or the working directory).&lt;/li&gt;
&lt;li&gt;(Optionally) deletes the temporary &lt;code&gt;temp_video&lt;/code&gt; / &lt;code&gt;temp_audio&lt;/code&gt; files once the final MP4 is confirmed to exist.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sanitizing the filename matters because YouTube titles can contain characters Windows doesn’t like, such as &lt;code&gt;:&lt;/code&gt; or &lt;code&gt;?&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A typical sanitiser does something like:&lt;/p&gt;

&lt;p&gt;import re&lt;br&gt;
def clean_name(title):&lt;br&gt;
    return re.sub(r'[&amp;lt;&amp;gt;:"/|?*]', '_', title)&lt;/p&gt;

&lt;p&gt;That prevents Windows Explorer from complaining.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Packaging into a standalone &lt;code&gt;.exe&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Python scripts normally require:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A Python interpreter,&lt;/li&gt;
&lt;li&gt;Your &lt;code&gt;.py&lt;/code&gt; files,&lt;/li&gt;
&lt;li&gt;Third-party modules (&lt;code&gt;yt_dlp&lt;/code&gt;, &lt;code&gt;customtkinter&lt;/code&gt;, etc.),&lt;/li&gt;
&lt;li&gt;And &lt;code&gt;ffmpeg.exe&lt;/code&gt; somewhere on disk.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s annoying to ship to non-technical users. So the project is bundled into a self-contained Windows executable.&lt;/p&gt;

&lt;p&gt;This was likely done with &lt;code&gt;auto-py-to-exe&lt;/code&gt;, which is a wrapper around &lt;code&gt;PyInstaller&lt;/code&gt; that gives you a point-and-click interface to build &lt;code&gt;.exe&lt;/code&gt;s.&lt;/p&gt;

&lt;p&gt;Here’s roughly what happens in packaging:&lt;/p&gt;

&lt;p&gt;1) Your Python source + libraries get analyzed.&lt;br&gt;
2) All the bytecode, plus resource files, plus &lt;code&gt;ffmpeg.exe&lt;/code&gt;, is stuffed into a single archive.&lt;br&gt;
3) PyInstaller’s bootloader (a small C program) is placed in front of that archive.&lt;br&gt;
   When you run &lt;code&gt;Youtube to mp4.exe&lt;/code&gt;, the bootloader:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creates a temporary extraction folder (often a &lt;code&gt;_MEIxxxxx&lt;/code&gt; folder in &lt;code&gt;%TEMP%&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Unpacks Python, your code, yt_dlp, ffmpeg, and all needed DLLs there.&lt;/li&gt;
&lt;li&gt;Executes your &lt;code&gt;main&lt;/code&gt; script as if you just ran &lt;code&gt;python main.py&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because of this, the &lt;code&gt;.exe&lt;/code&gt; you provided is fairly large — on the order of tens of megabytes. It’s not “just the script,” it’s Python runtime + libraries + ffmpeg + everything else.&lt;/p&gt;

&lt;p&gt;Advantages of this approach:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The end user does not need Python installed.&lt;/li&gt;
&lt;li&gt;The UI and download logic behave consistently across systems.&lt;/li&gt;
&lt;li&gt;You can add an icon and a nice filename so it feels like a normal Windows app.&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Error handling and UX polish&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There are a few user-experience choices baked into the current design:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Resizable window: solves clipped widgets (like the far-right toggle text).&lt;/li&gt;
&lt;li&gt;Quality slider / dropdown: instead of dumping a giant advanced list of formats (&lt;code&gt;248&lt;/code&gt;, &lt;code&gt;251&lt;/code&gt;, &lt;code&gt;bestvideo+bestaudio/best&lt;/code&gt; etc.), the tool shows “720p,” “1080p,” “4K,” etc.&lt;/li&gt;
&lt;li&gt;Bitrate slider: lets you choose file size vs quality without needing to know internal &lt;code&gt;tbr&lt;/code&gt; values.&lt;/li&gt;
&lt;li&gt;Progress messages: things like “Downloading video…”, “Merging audio…”, “Done!”. This gives feedback during long downloads.&lt;/li&gt;
&lt;li&gt;Graceful fallback: if 4K fails because YouTube blocks access, the tool can either tell you why or drop to a working format (like 360p progressive) instead of silently crashing.&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Putting it all together&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here’s the full lifecycle of one download request:&lt;/p&gt;

&lt;p&gt;1) User input&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You paste a YouTube URL into the GUI.&lt;/li&gt;
&lt;li&gt;You pick a resolution/bitrate with the sliders and toggles.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;2) Probe formats&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The app calls &lt;code&gt;yt_dlp&lt;/code&gt; in “info only” mode to list available formats and metadata.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;3) Pick strategy&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If there’s a progressive MP4 at or under the target quality: choose that.&lt;/li&gt;
&lt;li&gt;Otherwise, choose the best video-only stream that matches your quality/bitrate, and the best audio-only stream.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;4) Download&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The app downloads those streams.&lt;/li&gt;
&lt;li&gt;The GUI updates status as it goes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;5) Mux / Merge&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ffmpeg&lt;/code&gt; (bundled inside the .exe) merges video+audio into one MP4.&lt;/li&gt;
&lt;li&gt;No manual ffmpeg knowledge needed — it runs invisibly in the background.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;6) Cleanup and save&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The final MP4 is renamed using a cleaned-up video title.&lt;/li&gt;
&lt;li&gt;Temporary chunks get deleted.&lt;/li&gt;
&lt;li&gt;The GUI reports success.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;7) You watch the video&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You now have a normal &lt;code&gt;.mp4&lt;/code&gt; that will open in VLC, Windows Media Player, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Why this design works well&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;No external setup: Everything is in one EXE, so a non-technical user can double-click it on Windows and immediately use it.&lt;/li&gt;
&lt;li&gt;GUI instead of command line: People don’t have to memorize yt-dlp or ffmpeg arguments.&lt;/li&gt;
&lt;li&gt;Quality control: The app exposes “quality,” “resolution,” and “bitrate” as sliders / dropdowns instead of scary codec jargon.&lt;/li&gt;
&lt;li&gt;Automatic merge: The tool handles adaptive streaming (audio/video split) automatically, so HD and 4K downloads become a single click.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In short, the app is a friendly wrapper around a pretty advanced chain:&lt;br&gt;
scrape → choose formats → download streams → transcode/mux → save MP4,&lt;br&gt;
all orchestrated through a Python GUI and shipped as a Windows-native &lt;code&gt;.exe&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here is the repo! &lt;a href="https://github.com/Coolythecoder/Youtube-to-mp4" rel="noopener noreferrer"&gt;https://github.com/Coolythecoder/Youtube-to-mp4&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>ffmpeg</category>
      <category>customtkinter</category>
      <category>ytdlp</category>
    </item>
  </channel>
</rss>
