mirror of
https://github.com/ZHANGTIANYAO1/teamspeak-music-bot.git
synced 2026-10-01 20:42:50 +08:00
fix(player): set browser UA + Referer for Netease CDN to stop auto-skip
Netease's m701/m801.music.126.net CDN RST connections from FFmpeg's default Lavf UA. The bot's frame loop treats an early ffmpeg exit as trackEnd and advances the queue, which surfaced as songs auto-skipping mid-playlist. Add a browser UA + music.163.com Referer for these URLs, extract args into a tested buildFfmpegArgs(), and harden reconnect flags (delay_max 5 -> 30, plus reconnect_on_network_error / reconnect_on_http_error). Verified by A/B running ffmpeg against the same fresh CDN URL: legacy args got 0 bytes + "End of file" reading HTTP response; fixed args streamed the full track to completion. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
7eb96d9068
commit
f76500cfb2
3 files changed
+173
-7
No files matched your search
@@ -0,0 +1,73 @@
|
||||
// Empirically tests whether the browser UA + Referer headers fix the
|
||||
// connection resets we saw in bot.log against m701/m801.music.126.net.
|
||||
//
|
||||
// Spawns ffmpeg twice against the SAME fresh Netease CDN URL:
|
||||
// A) old args from before the fix (no headers, -reconnect_delay_max 5)
|
||||
// B) new args from after the fix (browser UA + Referer for music.126.net)
|
||||
// and reports bytes received + exit code + stderr-tail for each.
|
||||
|
||||
import { spawn } from "node:child_process";
|
||||
import { buildFfmpegArgs } from "../dist/audio/player.js";
|
||||
|
||||
const url = process.argv[2];
|
||||
if (!url) {
|
||||
console.error("usage: node scripts/test_netease_ua_fix.mjs <netease_cdn_url>");
|
||||
process.exit(2);
|
||||
}
|
||||
|
||||
const FFMPEG = "ffmpeg";
|
||||
const TIMEOUT_MS = 15_000;
|
||||
|
||||
function legacyArgs(u) {
|
||||
return [
|
||||
"-reconnect", "1",
|
||||
"-reconnect_streamed", "1",
|
||||
"-reconnect_delay_max", "5",
|
||||
"-i", u,
|
||||
"-f", "s16le",
|
||||
"-ar", "48000",
|
||||
"-ac", "2",
|
||||
"-acodec", "pcm_s16le",
|
||||
"-",
|
||||
];
|
||||
}
|
||||
|
||||
function runFfmpeg(label, args) {
|
||||
return new Promise((resolve) => {
|
||||
const proc = spawn(FFMPEG, args, { stdio: ["ignore", "pipe", "pipe"] });
|
||||
let bytes = 0;
|
||||
let stderrTail = "";
|
||||
let killed = false;
|
||||
|
||||
proc.stdout.on("data", (chunk) => {
|
||||
bytes += chunk.length;
|
||||
});
|
||||
proc.stderr.on("data", (chunk) => {
|
||||
stderrTail = (stderrTail + chunk.toString()).slice(-1500);
|
||||
});
|
||||
|
||||
const timer = setTimeout(() => {
|
||||
killed = true;
|
||||
proc.kill("SIGTERM");
|
||||
}, TIMEOUT_MS);
|
||||
|
||||
proc.on("exit", (code, signal) => {
|
||||
clearTimeout(timer);
|
||||
resolve({ label, bytes, code, signal, killed, stderrTail });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
console.log(`URL: ${url}\n`);
|
||||
|
||||
const a = await runFfmpeg("A) legacy args (no UA)", legacyArgs(url));
|
||||
console.log(`[A] code=${a.code} signal=${a.signal} killed=${a.killed} bytes=${a.bytes}`);
|
||||
console.log(` stderr-tail:\n${a.stderrTail.split("\n").slice(-6).map((l) => " " + l).join("\n")}\n`);
|
||||
|
||||
const b = await runFfmpeg("B) fixed args (browser UA + Referer)", buildFfmpegArgs(url, 0));
|
||||
console.log(`[B] code=${b.code} signal=${b.signal} killed=${b.killed} bytes=${b.bytes}`);
|
||||
console.log(` stderr-tail:\n${b.stderrTail.split("\n").slice(-6).map((l) => " " + l).join("\n")}\n`);
|
||||
|
||||
const aFailed = a.bytes === 0 && !a.killed && a.code !== 0;
|
||||
const bWorked = b.bytes > 100_000; // got real audio bytes
|
||||
console.log(`Verdict: legacy ${aFailed ? "FAILED (no bytes, exit code 1)" : "??"} ; fixed ${bWorked ? "WORKED (received audio)" : "??"}`);
|
||||
Reference in new issue
Block a user