modified: Dockerfile
modified: app.py
This commit is contained in:
@@ -11,6 +11,8 @@ RUN apt-get update && apt-get install -y \
|
||||
|
||||
COPY requirements.txt .
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
# Ensure yt-dlp is up-to-date so extractor fixes are applied
|
||||
RUN pip install --no-cache-dir -U yt-dlp
|
||||
|
||||
COPY . .
|
||||
|
||||
|
||||
64
app.py
64
app.py
@@ -444,24 +444,56 @@ async def _ensure_connected(ctx: commands.Context) -> Optional[discord.VoiceClie
|
||||
async def _ytdlp_extract(loop: asyncio.AbstractEventLoop, query: str) -> Optional[Dict]:
|
||||
if not ytdlp:
|
||||
return None
|
||||
def _extract():
|
||||
with ytdlp.YoutubeDL(get_ytdl_opts()) as ytdl:
|
||||
return ytdl.extract_info(query, download=False)
|
||||
try:
|
||||
info = await loop.run_in_executor(executor, _extract)
|
||||
if info is None:
|
||||
# Try extraction with multiple player_client hints if extraction fails due to player/nsig issues.
|
||||
# Start with the configured client, then fall back to common alternatives.
|
||||
preferred = os.getenv('YTDL_YT_CLIENT', 'android')
|
||||
candidates = [preferred]
|
||||
for c in ('web', 'tv', 'android_embedded', 'firetv'):
|
||||
if c not in candidates:
|
||||
candidates.append(c)
|
||||
|
||||
last_exc = None
|
||||
for client_hint in candidates:
|
||||
def _extract_with_client(client=client_hint):
|
||||
opts = get_ytdl_opts()
|
||||
# Override player_client for this attempt
|
||||
try:
|
||||
opts['extractor_args']['youtube']['player_client'] = [client]
|
||||
except Exception:
|
||||
opts.setdefault('extractor_args', {}).setdefault('youtube', {})['player_client'] = [client]
|
||||
with ytdlp.YoutubeDL(opts) as ytdl:
|
||||
return ytdl.extract_info(query, download=False)
|
||||
|
||||
try:
|
||||
info = await loop.run_in_executor(executor, _extract_with_client)
|
||||
if info is None:
|
||||
continue
|
||||
if 'entries' in info:
|
||||
info = info['entries'][0]
|
||||
return info
|
||||
except Exception as e:
|
||||
last_exc = e
|
||||
msg = str(e).lower()
|
||||
# If it's a cookies/sign-in issue, surface a helpful message and stop trying
|
||||
if 'sign in to confirm' in msg or 'use --cookies' in msg or 'pass cookies' in msg:
|
||||
print("❌ yt-dlp error: YouTube requires cookies to proceed.")
|
||||
print(" Provide YTDL_COOKIES_FILE or YTDL_COOKIES_B64 (Netscape cookies.txt).")
|
||||
traceback.print_exc()
|
||||
return None
|
||||
# If nsig/sabr or unsupported client warnings occurred, try next client hint
|
||||
if 'nsig extraction failed' in msg or 'sabr' in msg or 'unsupported client' in msg:
|
||||
print(f"⚠️ yt-dlp warning with client={client_hint}: {e}")
|
||||
# continue to try other clients
|
||||
continue
|
||||
# Otherwise, log and stop trying
|
||||
traceback.print_exc()
|
||||
return None
|
||||
if 'entries' in info:
|
||||
info = info['entries'][0]
|
||||
return info
|
||||
except Exception as e:
|
||||
# Make YouTube cookie issues clearer in logs
|
||||
msg = str(e)
|
||||
if 'Sign in to confirm you’re not a bot' in msg or 'Use --cookies' in msg or 'pass cookies' in msg:
|
||||
print("❌ yt-dlp error: YouTube requires cookies to proceed.")
|
||||
print(" Provide YTDL_COOKIES_FILE or YTDL_COOKIES_B64 (Netscape cookies.txt).")
|
||||
|
||||
# If we tried everything and failed, log last exception
|
||||
if last_exc:
|
||||
print(f"❌ All yt-dlp client attempts failed. Last error: {type(last_exc).__name__}: {last_exc}")
|
||||
traceback.print_exc()
|
||||
return None
|
||||
return None
|
||||
|
||||
async def _create_audio_source(loop: asyncio.AbstractEventLoop, search: str, volume: float):
|
||||
# Accept either URL or search text; prepend ytsearch1: if not a URL
|
||||
|
||||
Reference in New Issue
Block a user