Skip to content

Try not to access YT streams before they're available - #1028

Open
RJVB wants to merge 3 commits into
zaps166:masterfrom
RJVB:yt-respect-dt
Open

Try not to access YT streams before they're available#1028
RJVB wants to merge 3 commits into
zaps166:masterfrom
RJVB:yt-respect-dt

Conversation

@RJVB

@RJVB RJVB commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

YouTube (now?) provides an available_at timestamp for streams, and it seems that accessing them before that time can result in a 403 Forbidden error.

This commit introduces a simple fix that determines which of the streams of a given video is available last, and then does a non- blocking wait before attempting to open the selected streams. The wait is signalled via a statusbar message.

There are no side-effects other than that the wait is imposed also when pasting a YT video link directly into the playlist, apparently because this operation involves starting playback. This should be avoidable but will require more work.

#Closes: #1027

YouTube (now?) provides an `available_at` timestamp for streams,
and it seems that accessing them before that time can result in
a 403 Forbidden error.

This commit introduces a simple fix that determines which of the
streams of a given video is available last, and then does a non-
blocking wait before attempting to open the selected streams.
The wait is signalled via a statusbar message.

There are no side-effects other than that the wait is imposed
also when pasting a YT video link directly into the playlist,
apparently because this operation involves starting playback.
This should be avoidable but will require more work.

Committed from host : Bmbl
Comment thread src/modules/Extensions/YouTube.cpp Outdated
Comment thread src/modules/Extensions/YouTube.cpp Outdated
Comment thread src/modules/Extensions/YouTube.cpp Outdated
Comment thread src/modules/Extensions/YouTube.cpp Outdated
Comment thread src/modules/Extensions/YouTube.cpp
Comment thread src/modules/Extensions/YouTube.cpp Outdated
@RJVB

RJVB commented Jul 18, 2026 via email

Copy link
Copy Markdown
Contributor Author

Committed from host : Bmbl

@zaps166 zaps166 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Recently I noticed forbidden error on YouTube, so I can test it. Unfortunately, it's not fully working:

Extensions/YouTube: url for format "139" will be available at QDateTime(2026-07-25 12:24:32.000 CEST Qt::LocalTime) so in -0.432 s
Extensions/YouTube: url for format "249" will be available at QDateTime(2026-07-25 12:24:32.000 CEST Qt::LocalTime) so in -0.432 s
Extensions/YouTube: url for format "140" will be available at QDateTime(2026-07-25 12:24:32.000 CEST Qt::LocalTime) so in -0.432 s
Extensions/YouTube: url for format "251" will be available at QDateTime(2026-07-25 12:24:32.000 CEST Qt::LocalTime) so in -0.432 s
Extensions/YouTube: url for format "160" will be available at QDateTime(2026-07-25 12:24:32.000 CEST Qt::LocalTime) so in -0.432 s
Extensions/YouTube: url for format "278" will be available at QDateTime(2026-07-25 12:24:32.000 CEST Qt::LocalTime) so in -0.432 s
Extensions/YouTube: url for format "394" will be available at QDateTime(2026-07-25 12:24:32.000 CEST Qt::LocalTime) so in -0.432 s
Extensions/YouTube: url for format "133" will be available at QDateTime(2026-07-25 12:24:32.000 CEST Qt::LocalTime) so in -0.432 s
Extensions/YouTube: url for format "242" will be available at QDateTime(2026-07-25 12:24:32.000 CEST Qt::LocalTime) so in -0.432 s
Extensions/YouTube: url for format "395" will be available at QDateTime(2026-07-25 12:24:32.000 CEST Qt::LocalTime) so in -0.432 s
Extensions/YouTube: url for format "134" will be available at QDateTime(2026-07-25 12:24:32.000 CEST Qt::LocalTime) so in -0.432 s
Extensions/YouTube: url for format "18" will be available at QDateTime(2026-07-25 12:24:32.000 CEST Qt::LocalTime) so in -0.432 s
Extensions/YouTube: url for format "243" will be available at QDateTime(2026-07-25 12:24:32.000 CEST Qt::LocalTime) so in -0.432 s
Extensions/YouTube: url for format "396" will be available at QDateTime(2026-07-25 12:24:32.000 CEST Qt::LocalTime) so in -0.432 s
Extensions/YouTube: url for format "135" will be available at QDateTime(2026-07-25 12:24:32.000 CEST Qt::LocalTime) so in -0.432 s
Extensions/YouTube: url for format "244" will be available at QDateTime(2026-07-25 12:24:32.000 CEST Qt::LocalTime) so in -0.432 s
Extensions/YouTube: url for format "397" will be available at QDateTime(2026-07-25 12:24:32.000 CEST Qt::LocalTime) so in -0.432 s
Extensions/YouTube: url for format "298" will be available at QDateTime(2026-07-25 12:24:32.000 CEST Qt::LocalTime) so in -0.432 s
Extensions/YouTube: url for format "302" will be available at QDateTime(2026-07-25 12:24:32.000 CEST Qt::LocalTime) so in -0.432 s
Extensions/YouTube: url for format "398" will be available at QDateTime(2026-07-25 12:24:32.000 CEST Qt::LocalTime) so in -0.432 s
Extensions/YouTube: url for format "299" will be available at QDateTime(2026-07-25 12:24:32.000 CEST Qt::LocalTime) so in -0.432 s
Extensions/YouTube: url for format "303" will be available at QDateTime(2026-07-25 12:24:32.000 CEST Qt::LocalTime) so in -0.432 s
Extensions/YouTube: url for format "399" will be available at QDateTime(2026-07-25 12:24:32.000 CEST Qt::LocalTime) so in -0.432 s
[https @ 0x7f9adc74b7c0] HTTP error 403 Forbidden
[https @ 0x7f9adc764840] HTTP error 403 Forbidden

Comment thread src/modules/Extensions/YouTube.cpp Outdated
Comment thread src/modules/Extensions/YouTube.cpp Outdated
Comment thread src/modules/Extensions/YouTube.cpp Outdated
Comment thread src/modules/Extensions/YouTube.cpp Outdated
Comment thread src/modules/Extensions/YouTube.cpp Outdated
@RJVB

RJVB commented Jul 25, 2026 via email

Copy link
Copy Markdown
Contributor Author

@zaps166

zaps166 commented Jul 25, 2026

Copy link
Copy Markdown
Owner

Oh damn. What's the link to that video? Does yt-dlp succeed?

Video generally works, but fails once per few runs. It's not just one video (try https://www.youtube.com/watch?v=LXb3EKWsInQ). Same experience as without the patch.

Extensions/YouTube: url for format "139" will be available at QDateTime(2026-07-25 14:39:06.000 CEST Qt::LocalTime) so in -0.634 s
Extensions/YouTube: url for format "249" will be available at QDateTime(2026-07-25 14:39:06.000 CEST Qt::LocalTime) so in -0.634 s
Extensions/YouTube: url for format "140" will be available at QDateTime(2026-07-25 14:39:06.000 CEST Qt::LocalTime) so in -0.634 s
Extensions/YouTube: url for format "251" will be available at QDateTime(2026-07-25 14:39:06.000 CEST Qt::LocalTime) so in -0.634 s
Extensions/YouTube: url for format "160" will be available at QDateTime(2026-07-25 14:39:06.000 CEST Qt::LocalTime) so in -0.634 s
Extensions/YouTube: url for format "278" will be available at QDateTime(2026-07-25 14:39:06.000 CEST Qt::LocalTime) so in -0.634 s
Extensions/YouTube: url for format "330" will be available at QDateTime(2026-07-25 14:39:06.000 CEST Qt::LocalTime) so in -0.634 s
Extensions/YouTube: url for format "694" will be available at QDateTime(2026-07-25 14:39:06.000 CEST Qt::LocalTime) so in -0.634 s
Extensions/YouTube: url for format "133" will be available at QDateTime(2026-07-25 14:39:06.000 CEST Qt::LocalTime) so in -0.634 s
Extensions/YouTube: url for format "242" will be available at QDateTime(2026-07-25 14:39:06.000 CEST Qt::LocalTime) so in -0.634 s
Extensions/YouTube: url for format "331" will be available at QDateTime(2026-07-25 14:39:06.000 CEST Qt::LocalTime) so in -0.634 s
Extensions/YouTube: url for format "695" will be available at QDateTime(2026-07-25 14:39:06.000 CEST Qt::LocalTime) so in -0.634 s
Extensions/YouTube: url for format "134" will be available at QDateTime(2026-07-25 14:39:06.000 CEST Qt::LocalTime) so in -0.634 s
Extensions/YouTube: url for format "18" will be available at QDateTime(2026-07-25 14:39:06.000 CEST Qt::LocalTime) so in -0.634 s
Extensions/YouTube: url for format "243" will be available at QDateTime(2026-07-25 14:39:06.000 CEST Qt::LocalTime) so in -0.634 s
Extensions/YouTube: url for format "332" will be available at QDateTime(2026-07-25 14:39:06.000 CEST Qt::LocalTime) so in -0.634 s
Extensions/YouTube: url for format "696" will be available at QDateTime(2026-07-25 14:39:06.000 CEST Qt::LocalTime) so in -0.634 s
Extensions/YouTube: url for format "135" will be available at QDateTime(2026-07-25 14:39:06.000 CEST Qt::LocalTime) so in -0.634 s
Extensions/YouTube: url for format "244" will be available at QDateTime(2026-07-25 14:39:06.000 CEST Qt::LocalTime) so in -0.634 s
Extensions/YouTube: url for format "333" will be available at QDateTime(2026-07-25 14:39:06.000 CEST Qt::LocalTime) so in -0.634 s
Extensions/YouTube: url for format "697" will be available at QDateTime(2026-07-25 14:39:06.000 CEST Qt::LocalTime) so in -0.634 s
Extensions/YouTube: url for format "298" will be available at QDateTime(2026-07-25 14:39:06.000 CEST Qt::LocalTime) so in -0.634 s
Extensions/YouTube: url for format "302" will be available at QDateTime(2026-07-25 14:39:06.000 CEST Qt::LocalTime) so in -0.635 s
Extensions/YouTube: url for format "334" will be available at QDateTime(2026-07-25 14:39:06.000 CEST Qt::LocalTime) so in -0.635 s
Extensions/YouTube: url for format "698" will be available at QDateTime(2026-07-25 14:39:06.000 CEST Qt::LocalTime) so in -0.635 s
Extensions/YouTube: url for format "299" will be available at QDateTime(2026-07-25 14:39:06.000 CEST Qt::LocalTime) so in -0.635 s
Extensions/YouTube: url for format "303" will be available at QDateTime(2026-07-25 14:39:06.000 CEST Qt::LocalTime) so in -0.635 s
Extensions/YouTube: url for format "335" will be available at QDateTime(2026-07-25 14:39:06.000 CEST Qt::LocalTime) so in -0.635 s
Extensions/YouTube: url for format "699" will be available at QDateTime(2026-07-25 14:39:06.000 CEST Qt::LocalTime) so in -0.635 s
Extensions/YouTube: url for format "308" will be available at QDateTime(2026-07-25 14:39:06.000 CEST Qt::LocalTime) so in -0.635 s
Extensions/YouTube: url for format "336" will be available at QDateTime(2026-07-25 14:39:06.000 CEST Qt::LocalTime) so in -0.635 s
Extensions/YouTube: url for format "700" will be available at QDateTime(2026-07-25 14:39:06.000 CEST Qt::LocalTime) so in -0.635 s
Extensions/YouTube: url for format "315" will be available at QDateTime(2026-07-25 14:39:06.000 CEST Qt::LocalTime) so in -0.635 s
Extensions/YouTube: url for format "337" will be available at QDateTime(2026-07-25 14:39:06.000 CEST Qt::LocalTime) so in -0.635 s
Extensions/YouTube: url for format "701" will be available at QDateTime(2026-07-25 14:39:06.000 CEST Qt::LocalTime) so in -0.635 s
[25 Jul 2026 14:39:06.635] Waiting for 1s as required by YouTube
[https @ 0x7f67940ddc80] HTTP error 403 Forbidden
[https @ 0x7f6794000fc0] HTTP error 403 Forbidden

Is there a difference with a regular, readable int() cast??

No difference, only syntax 😅

@RJVB

RJVB commented Jul 25, 2026 via email

Copy link
Copy Markdown
Contributor Author

@zaps166

zaps166 commented Jul 25, 2026

Copy link
Copy Markdown
Owner

Now hard coded 5 seconds (Waiting for 5s as required by YouTube) and still the same issue (once per few stop/play):

[https @ 0x7f2cfc009a40] HTTP error 403 Forbidden
[https @ 0x7f2cfc0070c0] HTTP error 403 Forbidden

Also you have a loop which doesn't check for youTubeDL.isAborted() - it should check for this instead of using event loop (it's running in thread, so the loop must abort if another thread asks for stop, but it only waits in separate thread, so no need for event loop i guess).

@RJVB

RJVB commented Jul 25, 2026 via email

Copy link
Copy Markdown
Contributor Author

@RJVB

RJVB commented Jul 25, 2026 via email

Copy link
Copy Markdown
Contributor Author

Committed from host : Bmbl
@RJVB

RJVB commented Jul 25, 2026 via email

Copy link
Copy Markdown
Contributor Author

@zaps166

zaps166 commented Jul 30, 2026

Copy link
Copy Markdown
Owner

FWIW, the negative dt values are <-2s for me.

Maybe you have much slower machine. When I limit my CPU to 500 MHz, I also have ~-2s. It looks like time obtained by yt-dlp and time compared in QMPlay2 - ~2 seconds elapsed between point 1 and 2, so no need to wait at all. Anyway waiting doesn't help, I still can reproduce forbidden.

Maybe you should check for cookies, referer, user agent (it's QMPlay2 by default, maybe youtube randomly rejects it?).

@RJVB

RJVB commented Jul 30, 2026 via email

Copy link
Copy Markdown
Contributor Author

@zaps166

zaps166 commented Jul 31, 2026

Copy link
Copy Markdown
Owner

So what available_at means? I think it returns time of my PC (in UTC) when temporary URL was generated.

Maybe my occasional 403 reason is different than yours.

I don't change anything to the referer or user agent. I do know that the use of firefox's cookies makes a difference in the stream formats that yt-dlp returns, but the rejection occurs afterwards.

I mean that you may try to use standard user agent instead of QMPlay2 😄 and check results.

@RJVB

RJVB commented Jul 31, 2026 via email

Copy link
Copy Markdown
Contributor Author

@zaps166

zaps166 commented Aug 18, 2026

Copy link
Copy Markdown
Owner

There are more and more 403 errors, also in M3U8 HLS live streams (also in mpv and ffmpeg) - live stream plays for less than a minute and freezes with 403 errors.

@RJVB

RJVB commented Aug 18, 2026 via email

Copy link
Copy Markdown
Contributor Author

@zaps166

zaps166 commented Aug 18, 2026

Copy link
Copy Markdown
Owner

🤔 I don't use cookies from browser

@RJVB

RJVB commented Aug 18, 2026 via email

Copy link
Copy Markdown
Contributor Author

@zaps166

zaps166 commented Aug 18, 2026

Copy link
Copy Markdown
Owner

I see some posts there, but skimmed only. I tried nightly yt-dlp - same issue - downloads 39 seconds of live stream and then 403.

./yt-dlp "https://www.youtube.com/watch?v=..."
...
[https @ 0x55aae5d93fc0] HTTP error 403 Forbidden
[in#0/hls @ 0x55aae5284dc0] keepalive request failed for 'https://.../seg.ts' with error: 'Server returned 403 Forbidden (access denied)' when opening url, retrying with new connection

However URL extracted using "Video Download Helper" works properly 🤔

@RJVB

RJVB commented Aug 18, 2026 via email

Copy link
Copy Markdown
Contributor Author

@zaps166

zaps166 commented Aug 18, 2026

Copy link
Copy Markdown
Owner

I also got confirmation that not waiting until the available_at time is likely to throw 403 errors

Ok, but I want to test it; so far everything throws 403 xD

and that update channel switches are permanent.

Understandable if the downloaded binary is from nightly channel, it'll download updates from that channel, too.

It would help if you'd add a 24h update timer to the update-on-startup, or an "update now" button, I've been meaning to bring that up a while now. ;)

Instead of restarting QMPlay2? 24h timetout to re-check for updates seems to be good idea.

You can hopefully just wait until that livestream is finished and then watch it "in the replay".

No if it's permanent live stream (TV).

@RJVB

RJVB commented Aug 18, 2026 via email

Copy link
Copy Markdown
Contributor Author

@zaps166

zaps166 commented Aug 18, 2026

Copy link
Copy Markdown
Owner

It's working so far 😄

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.

Why does this YT video refuse to play?

2 participants