Repository navigation
fix(youtube): run yt-dlp extraction off the event loop - #199
Merged
Merged
Conversation
YouTubeSearch ran the whole yt-dlp chain (info, optional second-stage extraction, first valid search entry, audio format) synchronously inside the async command, freezing the event loop for seconds per !yt/!yts: playing clips stopped being fed and RCON/SourceMod traffic queued up. - Move the chain into one helper, _extract_youtube_audio, executed with asyncio.to_thread. It returns only (title, audio url, duration, view_count) so the full info dict is released when the thread returns. - Handle every extraction failure in one place: log it, send the player a private message, return 1. Raw yt-dlp errors no longer reach all chat. - Tolerate None/missing duration and view_count: show "?" and only call SetDuration when the duration is a positive number. Closes #186 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
16 tasks done
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes the three problems reported in #186, all in
YouTubeSearch(src/torchlight/Commands.py). Nothing else is touched.1. yt-dlp extraction no longer blocks the event loop
Why:
get_url_youtube_info(),get_first_valid_entry()andget_audio_format()are synchronous and network-heavy (aytsearch3:query routinely takes several seconds, more whenget_first_valid_entryretries entries). They ran directly inside the async_func, so the event loop was frozen the whole time: playing clips stopped being fed to the voice server and RCON/SourceMod traffic queued up. This may help with #119 and #34, but this PR does not claim to fix them.Change: the whole chain (info → optional second-stage extraction when
titleis missing andurlis present → first valid search entry forYoutubeSearch→ audio format URL) now lives in one static helper,YouTubeSearch._extract_youtube_audio, executed withawait asyncio.to_thread(...). The helper returns only(title, audio_url, duration, view_count), so the full info dict (formats, thumbnails, entries) is released as soon as the thread returns instead of staying alive for the rest of the command.2. One error path, private message only
Why: the second-stage extractions and
get_audio_formatwere outside thetry/except, so raw yt-dlp errors fell through toCommandHandler's generic handler and were echoed to all chat.Change: every failure of the helper is handled in the existing single
except: log it, send the player the existing private message ("An error as occured while trying to retrieve youtube metadata."), return 1.3.
Noneduration / view count no longer crash the commandWhy:
durationandview_countcan beNone(live streams, some extractors), which raisedTypeErrorintimedelta(seconds=None)/int(None)/float(None).Change: missing or non-numeric values are shown as
?in the chat line, andSetDurationis only called when the duration is a positive number.Banned keywords,
last_url, cookies/proxy handling,real_timeand the chat output format are unchanged.Test plan
Verified locally (throwaway script, not committed: it monkeypatches the
URLInfofunctions used byCommands.pyand stubsTorchlight/AudioManager):time.sleep, 1.5 s across search + first entry) with a concurrent ticker task: 25 ticks with this PR, 0 ticks on master (loop frozen).Some song | 0:03:32 | 1234,SetDuration(212.0),last_urlset, clip played.get_first_valid_entryerror and "no audio format" error: return 1, one private message, nothing in all chat (on master the second-stage error escapes the handler).duration/view_count=Noneand keys missing: chat shows| ? | ?, clip plays,SetDurationnot called.urlredirect, float duration/views and&t=30start time.ruff check .,ruff format --check .,mypy: no new errors (only the 3 known baseline errors fixed by CI: Python Linting is red on master since the Python 3.12 bump (ruff UP041, mypy arg-type) #178's PR).Needs a live server:
!yts <keywords>and!yt <url>while another clip plays: no audio cut-out during the search.!yton a live stream: plays with? | ?metadata.!ytswith an unplayable query: only the caller gets the private error.No VERSION bump (batch policy, see #177).
Closes #186
Part of #177
🤖 Generated with Claude Code