From 06c2aac6ef8c80a9377b57ede8eb36c2a6f44033 Mon Sep 17 00:00:00 2001 From: Ksan Date: Sat, 29 Aug 2026 18:48:55 +0200 Subject: [PATCH] enable youtube oauth for login-gated tracks --- .env.example | 7 +++++++ README.md | 35 +++++++++++++++++++++++++++++++++++ lavalink/application.yml | 17 +++++++++++++++++ 3 files changed, 59 insertions(+) diff --git a/.env.example b/.env.example index f0cf661..962d866 100644 --- a/.env.example +++ b/.env.example @@ -18,6 +18,13 @@ LAVALINK_URI=ws://localhost:2333 # match. Set a strong value — do NOT ship the youshallnotpass default. LAVALINK_PASSWORD=change-me +# YouTube OAuth refresh token, used for tracks YouTube refuses to serve without +# a login (age-restricted, "sign in to confirm you're not a bot"). Leave this +# commented out on the first run: Lavalink will log a google.com/device code, +# and after you authorize it logs the refresh token to paste here. Use a +# throwaway Google account. Read by the Lavalink container, not the bot. +#PLUGINS_YOUTUBE_OAUTH_REFRESHTOKEN= + # Path to the catchphrases file (one phrase per line). Optional; defaults to # catchphrases.txt in the working directory. CATCHPHRASES_FILE=catchphrases.txt diff --git a/README.md b/README.md index e039676..4b4a8b7 100644 --- a/README.md +++ b/README.md @@ -115,6 +115,41 @@ bot image and runs it alongside Lavalink. You only need Docker — no JDK. The bot connects to Lavalink over the internal Docker network automatically, so you don't set `LAVALINK_URI` yourself here. +## YouTube tracks that need a login + +Some tracks — age-restricted ones, and anything YouTube decides to gate behind +"Sign in to confirm you're not a bot" — won't load on the anonymous clients. The +`TV` client can play them, but only with a linked Google account, so +`lavalink/application.yml` enables the plugin's OAuth flow. **Use a throwaway +Google account: Google does ban accounts for this.** + +One-time setup: + +```bash +docker compose up -d lavalink +docker compose logs -f lavalink +``` + +The logs print something like: + +``` +OAUTH INTEGRATION: To give youtube-source access to your account, go to +https://www.google.com/device and enter code XXXX-XXXX +``` + +Open that page, enter the code, and approve. Lavalink then logs the refresh +token. Put it in `.env`: + +``` +PLUGINS_YOUTUBE_OAUTH_REFRESHTOKEN= +``` + +and `docker compose up -d lavalink` again. Compose already passes `.env` into the +Lavalink container, and the variable name maps onto +`plugins.youtube.oauth.refreshToken`, so later restarts skip the device flow. +Everything that already worked keeps using the anonymous clients — `TV` is last +in the client list and only gets used when the others are refused. + ## Notes - Queue state is kept in memory, so it resets if the bot restarts. diff --git a/lavalink/application.yml b/lavalink/application.yml index 9fe89d4..0324ed7 100644 --- a/lavalink/application.yml +++ b/lavalink/application.yml @@ -27,13 +27,30 @@ plugins: youtube: enabled: true allowSearch: true # enables the "ytsearch:" queries the bot falls back to + # Tried in order; the first one that can load the track wins. TV is last + # because it needs a signed-in account (see oauth below), but it's the only + # client that plays age-restricted / "sign in to confirm you're not a bot" + # tracks, so it's the fallback when the others get rejected. clients: - MUSIC - WEB - WEBEMBEDDED - ANDROID_VR + - TV + oauth: + # Links a Google account to the TV client. On first start with no refresh + # token, Lavalink logs a google.com/device code — open it, enter the code, + # and the plugin then logs a refresh token. Put that token in .env as + # PLUGINS_YOUTUBE_OAUTH_REFRESHTOKEN (docker-compose already passes .env + # into the Lavalink container, and Spring binds that name onto this key) + # so the device flow is skipped on every later start. + # + # Use a throwaway Google account. Google does ban accounts for this. + enabled: true logging: level: root: INFO lavalink: INFO + # Prints the device code and, after you authorize, the refresh token. + dev.lavalink.youtube.http.YoutubeOauth2Handler: INFO