Skip to content

🐛 Fix YouTube streaming black screen by passing HTTP headers to VLC#251

Open
WilliamTahar wants to merge 2 commits intojeffshee:masterfrom
WilliamTahar:fix-back-screen-of-youtube-link-video
Open

🐛 Fix YouTube streaming black screen by passing HTTP headers to VLC#251
WilliamTahar wants to merge 2 commits intojeffshee:masterfrom
WilliamTahar:fix-back-screen-of-youtube-link-video

Conversation

@WilliamTahar
Copy link
Copy Markdown

Summary

YouTube streaming mode (MODE_STREAM) currently results in a black screen because VLC does not send the HTTP headers required by YouTube (notably User-Agent and Referer). This PR extracts HTTP headers from yt-dlp and forwards them to VLC using its native media options, restoring YouTube stream playback.

This addresses the issues reported in #196, #166, and #214 where users experience black screens or broken streaming when using YouTube URLs.

Problem

When a user sets a YouTube URL in streaming mode, the following happens:

  1. yt-dlp correctly extracts the direct video/audio stream URLs along with HTTP headers
  2. However, yt_utils.py discards these headers and only returns the raw URLs
  3. video_player.py passes the bare URLs to VLC without any HTTP headers
  4. YouTube's CDN rejects the requests (missing User-Agent / Referer), resulting in a black screen

This issue has become more prominent as YouTube has tightened its request validation in recent months.

Changes

src/yt_utils.py

  • Extract HTTP headers from yt-dlp info dict and individual format entries
  • Ensure a default User-Agent is always present (YouTube blocks requests without one)
  • Ensure a default Referer is set to the source URL (YouTube validates this)
  • Propagate headers to all formats that don't have their own
  • Return headers alongside URLs from get_best_audio() (now returns (url, headers)) and get_optimal_video() (now returns (url, width, height, headers))
  • Add ValueError when no audio or video format is found, instead of failing silently

src/player/video_player.py

  • media_new(): Pass User-Agent and Referer to VLC via native options (:http-user-agent, :http-referrer)
  • add_audio_track(): Apply headers to the player's media for the audio slave track. Also fixes passing a URL string (not a Media object) to add_slave(), which previously caused a ctypes.ArgumentError
  • MODE_STREAM block: Receive and forward headers from yt_utils, add :network-caching=3000 for smoother streaming, add info/debug logging for stream URLs and headers, wrap in try/except with detailed error logging

Backward compatibility

  • Local video mode (MODE_VIDEO) is completely unaffected — http_headers defaults to None and all existing code paths remain unchanged
  • Webpage mode (MODE_WEBPAGE) is untouched
  • The return type changes in yt_utils.py only affect callers inside video_player.py's MODE_STREAM block, which is updated accordingly
  • Works with any site supported by yt-dlp, not just YouTube

Testing

Tested manually on Kubuntu (KDE, Wayland via XWayland, Intel GPU):

  • YouTube live streams: working (was black screen before)
  • YouTube regular videos in stream mode: working (was black screen before)
  • Local video files: still working, no regression
  • Multi-monitor setup: working on both monitors

Note on yt-dlp version

Users running an older yt-dlp (< 2025.10) may still experience issues due to YouTube's SABR streaming protocol changes (see yt-dlp#12482). Updating yt-dlp to the latest version is recommended. This is independent of this PR but worth noting in documentation or release notes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant