yb.youtube.auth¶
OAuth 2.0 plumbing for the YouTube Data API v3.
Runs the installed-app consent flow once (browser), caches the token, and
refreshes it silently thereafter. Needs only google-api-python-client +
google-auth-oauthlib (pip install 'yb[youtube]') and an OAuth client of
type Desktop app — point client_secrets_file at its JSON or set
$YOUTUBE_CLIENT_SECRETS_FILE / $GOOGLE_CLIENT_SECRETS_FILE.
No gcloud required: creating the project / enabling the API / making the
OAuth client is all doable in the Google Cloud console (the yb-setup skill
walks through it).
Module Attributes
Upload + force-ssl (the latter is needed for captions.insert and thumbnails.set). |
|
|
|
How long consent may wait for its redirect before giving up. |
Functions
Default OAuth client-secrets location: |
|
Cached OAuth token location ( |
|
|
Return OAuth user credentials, running the consent flow if needed. |
|
Build a YouTube Data API v3 service object. |
Exceptions
Consent is needed and this process cannot obtain it. |
- yb.youtube.auth.CONSENT_MODES = ('local', 'paste')¶
"local"waits for a redirect on this machine’slocalhost;"paste"is two-step and needs no shared network (seeyb.youtube.paste_consent).- Type:
Ways to obtain consent
- exception yb.youtube.auth.ConsentRequired[source]¶
Bases:
RuntimeErrorConsent is needed and this process cannot obtain it.
Raised instead of starting a consent flow that nobody can complete. The alternative is worse than an error:
run_local_serverprints a URL to a stdout nobody is reading and waits onlocalhostfor a redirect that will never arrive, so an automated caller blocks rather than failing. That has happened — an upload stopped dead mid-script and read as a slow network for hours, when the underlying cause was one line ofinvalid_grant.
- yb.youtube.auth.DEFAULT_CONSENT_TIMEOUT_S = 300.0¶
How long consent may wait for its redirect before giving up.
The library’s own default is “wait indefinitely”, which is not a good default for anything: a caller that cannot complete consent then blocks rather than failing, and an automated upload reads as a slow network until someone thinks to run
ps. Five minutes is long enough for a human to find the tab and click through an unverified-app warning, and short enough that a machine finds out today. Passtimeout_seconds=Nonefor the old behaviour.
- yb.youtube.auth.DEFAULT_SCOPES = ['https://www.googleapis.com/auth/youtube.upload', 'https://www.googleapis.com/auth/youtube.force-ssl']¶
Upload + force-ssl (the latter is needed for captions.insert and thumbnails.set).
- yb.youtube.auth.default_client_secrets_file()[source]¶
Default OAuth client-secrets location:
<config dir>/client_secret.json.Used when neither
client_secrets_file=nor the env vars are set, so all ofyb’s state can live in one directory next to the token.- Return type:
- yb.youtube.auth.default_token_file()[source]¶
Cached OAuth token location (
$XDG_CONFIG_HOMEor~/.config).- Return type:
- yb.youtube.auth.get_credentials(*, client_secrets_file=None, token_file=None, scopes=['https://www.googleapis.com/auth/youtube.upload', 'https://www.googleapis.com/auth/youtube.force-ssl'], open_browser=True, port=0, timeout_seconds=300.0, interactive=True, consent='local', authorization_response=None)[source]¶
Return OAuth user credentials, running the consent flow if needed.
First use runs the installed-app consent flow and caches the token to
token_fileso later calls are non-interactive. Expired tokens are refreshed automatically.Pass
interactive=Falsewhen nobody can answer a consent prompt — a cron job, a queue worker, an agent. Consent is then never started; a token that cannot be refreshed raisesConsentRequirednaming the cause and the fix. This is not an edge case: an OAuth client left in “Testing” rotates refresh tokens out after about seven days, so anything scheduled hits it weekly.Even with the default
interactive=Truethe call can no longer hang: consent is bounded bytimeout_seconds(DEFAULT_CONSENT_TIMEOUT_S), and a timeout is reported as the sameConsentRequired, because “nobody answered” and “nobody could answer” want the same thing done about them.Consent always goes through a temporary local web server on
port(0picks a free one), because Google retired the copy-paste “out-of-band” flow in 2022.open_browser=Falseonly stops the browser from being launched: the authorization URL is printed instead, and the redirect must still reach that local server.Headless recipe: pass
interactive=True(there is no terminal, so the default would refuse),open_browser=Falseand a fixedport=, then forward that port from the machine holding the browser (ssh -L <port>:localhost:<port> <host>). Nothing needs registering in the Cloud console — the Desktop app client this module requires accepts anylocalhostport, which is also why theport=0default works.The call blocks until the redirect arrives, bounded by
timeout_seconds(defaultDEFAULT_CONSENT_TIMEOUT_S; passNonefor the library’s “wait indefinitely”, which is what this used to do).**No shared
localhost? Use**consent="paste". Consent then needs no running server and no waiting: the first call returns by raisingConsentPendingcarrying the URL to open (anywhere — a phone will do); the browser’s redirect tolocalhostfails to load, and the second call passes that address-bar URL (or just itscode) asauthorization_response=to finish and cache the token. The two calls may be separate turns or separate processes;yb authis the command-line form.portonly names the (unreachable) redirect.These keywords ride
**cred_kwargsthroughget_service()and the publishing helpers. The few entry points that take none (notablyyb.music.publish.publish_folder()) still work headlessly: call this once to mint the token, after which nothing prompts again.
- yb.youtube.auth.get_service(*, credentials=None, **cred_kwargs)[source]¶
Build a YouTube Data API v3 service object.
cred_kwargsare forwarded toget_credentials()(token_file=,open_browser=,port=, …) unlesscredentialsis given.