Skip to content

Commit 859031f

Browse files
committed
refactor: remove cookie health probe and bitrate downgrade retry chain
Eliminates the ~240ms+ per-song retry overhead introduced by the MUSIC_U cookie health detection mechanism and the bitrate-downgrade retry logic. When a FLAC request returned 320kbps instead of 999kbps, the old code retried up to 3 times (~80ms each) before accepting the fallback URL. With MUSIC_U cookies this path was hit on every request. Removed: - MusicUCookieHealth enum, probe methods, and health cache (music_api.rs) - should_retry_primary_after_quality_downgrade / retry_primary_bitrate_url / retry_attempts_for_primary_unavailable functions - cookie health probe call-site and downgrade warning flow (bot.rs) - MP3_MAX_BITRATE_BPS, BITRATE_PROBE_TOLERANCE_BPS, COOKIE_HEALTH_PROBE_MAX_BITRATE constants - should_probe_cookie_health / build_cookie_expired_warning_text helpers - All related tests (8 removed, 2 rewritten to document new behaviour) The fallback URL is now accepted immediately without any retry. Verified: cargo fmt/check/clippy -D warnings all clean, 154/154 tests pass.
1 parent f23af52 commit 859031f

File tree

2 files changed

+24
-511
lines changed

2 files changed

+24
-511
lines changed

src/bot.rs

Lines changed: 5 additions & 159 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use crate::audio_buffer::{AudioBuffer, ThumbnailBuffer};
2424
use crate::config::{Config, CoverMode, UploadLogLevel};
2525
use crate::database::{Database, SongInfo};
2626
use crate::error::{BotError, Result};
27-
use crate::music_api::{MusicApi, MusicUCookieHealth, format_artists};
27+
use crate::music_api::{MusicApi, format_artists};
2828
use crate::utils::{
2929
clean_filename, ensure_dir, extract_first_url, parse_music_id, throughput_mbps, update_peak,
3030
};
@@ -993,7 +993,6 @@ async fn process_music(
993993
// Send status message and fetch song detail+URL in parallel
994994
let status_init_start = std::time::Instant::now();
995995
let bitrate_candidates = url_bitrate_candidates(state.music_api.music_u.is_some());
996-
let primary_bitrate = bitrate_candidates.first().copied().unwrap_or(0);
997996

998997
let status_fut = bot
999998
.send_message(msg.chat.id, "🔄 正在获取歌曲信息...")
@@ -1031,34 +1030,6 @@ async fn process_music(
10311030
return Ok(());
10321031
}
10331032

1034-
let has_music_u = state.music_api.music_u.is_some();
1035-
let should_probe_cookie = should_probe_cookie_health(has_music_u, primary_bitrate, song_url.br);
1036-
let cookie_quality_downgraded = if should_probe_cookie {
1037-
match state.music_api.probe_music_u_health().await {
1038-
MusicUCookieHealth::Unhealthy => true,
1039-
MusicUCookieHealth::Healthy => {
1040-
tracing::debug!(
1041-
"MUSIC_U health probe is healthy for music_id {} (requested {}, got {}), skip cookie warning",
1042-
music_id,
1043-
primary_bitrate,
1044-
song_url.br
1045-
);
1046-
false
1047-
}
1048-
MusicUCookieHealth::Unknown => {
1049-
tracing::warn!(
1050-
"MUSIC_U health probe is inconclusive for music_id {} (requested {}, got {}), skip cookie warning",
1051-
music_id,
1052-
primary_bitrate,
1053-
song_url.br
1054-
);
1055-
false
1056-
}
1057-
}
1058-
} else {
1059-
false
1060-
};
1061-
10621033
let pre_upload_path_start = std::time::Instant::now();
10631034

10641035
// Update status (fire-and-forget to overlap with download start)
@@ -1083,8 +1054,6 @@ async fn process_music(
10831054
state,
10841055
song_detail,
10851056
&song_url,
1086-
primary_bitrate,
1087-
cookie_quality_downgraded,
10881057
&status_msg,
10891058
pre_upload_path_start,
10901059
&artists,
@@ -1107,8 +1076,6 @@ async fn download_and_send_music(
11071076
state: &Arc<BotState>,
11081077
song_detail: Arc<crate::music_api::SongDetail>,
11091078
song_url: &crate::music_api::SongUrl,
1110-
requested_primary_bitrate: u64,
1111-
cookie_quality_downgraded: bool,
11121079
status_msg: &Message,
11131080
pre_upload_path_start: std::time::Instant,
11141081
artists: &str,
@@ -1292,23 +1259,15 @@ async fn download_and_send_music(
12921259
);
12931260
let (mut audio_buffer, downloaded) = downloaded_result?;
12941261
let _upload_permit = upload_permit_result?;
1295-
let should_remove_song_cache = should_remove_song_cache_after_partial_failure(
1296-
cover_retry_exhausted,
1297-
cookie_quality_downgraded,
1298-
);
1262+
let should_remove_song_cache =
1263+
should_remove_song_cache_after_partial_failure(cover_retry_exhausted);
12991264

13001265
if cover_retry_exhausted {
13011266
tracing::warn!(
13021267
"Cover fetch failed after retries for music_id {}. Audio will be sent without cover and cache will be removed",
13031268
song_id
13041269
);
13051270
}
1306-
if cookie_quality_downgraded {
1307-
tracing::warn!(
1308-
"Detected downgraded bitrate for music_id {} (MUSIC_U health probe unhealthy). Audio will still be sent and cache will be removed",
1309-
song_id
1310-
);
1311-
}
13121271

13131272
tracing::debug!(
13141273
"Audio download completed: {} bytes (mode: {})",
@@ -1575,22 +1534,6 @@ async fn download_and_send_music(
15751534
// Delete status message
15761535
bot.delete_message(msg.chat.id, status_msg.id).await.ok();
15771536

1578-
if cookie_quality_downgraded {
1579-
let warning_text =
1580-
build_cookie_expired_warning_text(requested_primary_bitrate, song_info.bit_rate);
1581-
if let Err(e) = bot
1582-
.send_message(msg.chat.id, warning_text)
1583-
.reply_parameters(ReplyParameters::new(msg.id))
1584-
.await
1585-
{
1586-
tracing::warn!(
1587-
"Failed to send cookie-expired warning for music_id {}: {}",
1588-
song_id,
1589-
e
1590-
);
1591-
}
1592-
}
1593-
15941537
Ok(())
15951538
}
15961539

@@ -1743,43 +1686,8 @@ fn url_bitrate_candidates(has_music_u: bool) -> &'static [u64] {
17431686
}
17441687
}
17451688

1746-
// Provider may report slightly above nominal 320 kbps; keep a small tolerance for probe trigger.
1747-
const MP3_MAX_BITRATE_BPS: u64 = 320_000;
1748-
const BITRATE_PROBE_TOLERANCE_BPS: u64 = 5_000;
1749-
const COOKIE_HEALTH_PROBE_MAX_BITRATE: u64 = MP3_MAX_BITRATE_BPS + BITRATE_PROBE_TOLERANCE_BPS;
1750-
1751-
fn should_probe_cookie_health(
1752-
has_music_u: bool,
1753-
requested_primary_bitrate: u64,
1754-
returned_bitrate: u64,
1755-
) -> bool {
1756-
has_music_u
1757-
&& requested_primary_bitrate > COOKIE_HEALTH_PROBE_MAX_BITRATE
1758-
&& returned_bitrate > 0
1759-
&& returned_bitrate <= COOKIE_HEALTH_PROBE_MAX_BITRATE
1760-
}
1761-
1762-
fn should_remove_song_cache_after_partial_failure(
1763-
cover_retry_exhausted: bool,
1764-
cookie_quality_downgraded: bool,
1765-
) -> bool {
1766-
cover_retry_exhausted || cookie_quality_downgraded
1767-
}
1768-
1769-
fn build_cookie_expired_warning_text(
1770-
requested_primary_bitrate: u64,
1771-
actual_bitrate_bps: i64,
1772-
) -> String {
1773-
if requested_primary_bitrate > 0 && actual_bitrate_bps > 0 {
1774-
format!(
1775-
"⚠️ 检测到 MUSIC_U Cookie 可能已失效,音质已从 {} kbps 降至 {} kbps。\n已发送可用音频,请尽快更新 Cookie。",
1776-
format_bitrate_kbps(requested_primary_bitrate as i64),
1777-
format_bitrate_kbps(actual_bitrate_bps)
1778-
)
1779-
} else {
1780-
"⚠️ 检测到 MUSIC_U Cookie 可能已失效,当前音质已降级。\n已发送可用音频,请尽快更新 Cookie。"
1781-
.to_string()
1782-
}
1689+
fn should_remove_song_cache_after_partial_failure(cover_retry_exhausted: bool) -> bool {
1690+
cover_retry_exhausted
17831691
}
17841692

17851693
const MESSAGE_TASK_LINK_HINTS: [&str; 3] = ["music.163.com", "163cn.tv", "163cn.link"];
@@ -2765,68 +2673,6 @@ mod tests {
27652673
assert_eq!(super::url_bitrate_candidates(false), &[320_000, 128_000]);
27662674
}
27672675

2768-
#[test]
2769-
fn cookie_health_probe_trigger_handles_320_neighborhood() {
2770-
assert!(super::should_probe_cookie_health(
2771-
true,
2772-
999_000,
2773-
super::MP3_MAX_BITRATE_BPS
2774-
));
2775-
assert!(super::should_probe_cookie_health(
2776-
true,
2777-
999_000,
2778-
super::MP3_MAX_BITRATE_BPS + 1
2779-
));
2780-
assert!(super::should_probe_cookie_health(
2781-
true,
2782-
999_000,
2783-
super::COOKIE_HEALTH_PROBE_MAX_BITRATE
2784-
));
2785-
assert!(!super::should_probe_cookie_health(
2786-
true,
2787-
999_000,
2788-
super::COOKIE_HEALTH_PROBE_MAX_BITRATE + 1
2789-
));
2790-
assert!(!super::should_probe_cookie_health(
2791-
false,
2792-
999_000,
2793-
super::MP3_MAX_BITRATE_BPS
2794-
));
2795-
assert!(!super::should_probe_cookie_health(
2796-
true,
2797-
super::MP3_MAX_BITRATE_BPS,
2798-
super::MP3_MAX_BITRATE_BPS
2799-
));
2800-
}
2801-
2802-
#[test]
2803-
fn partial_failure_should_remove_song_cache() {
2804-
assert!(super::should_remove_song_cache_after_partial_failure(
2805-
true, false
2806-
));
2807-
assert!(super::should_remove_song_cache_after_partial_failure(
2808-
false, true
2809-
));
2810-
assert!(!super::should_remove_song_cache_after_partial_failure(
2811-
false, false
2812-
));
2813-
}
2814-
2815-
#[test]
2816-
fn cookie_expired_warning_text_contains_requested_and_actual_bitrate() {
2817-
let text = super::build_cookie_expired_warning_text(999_000, 320_000);
2818-
assert!(text.contains("Cookie"));
2819-
assert!(text.contains("999"));
2820-
assert!(text.contains("320"));
2821-
}
2822-
2823-
#[test]
2824-
fn cookie_expired_warning_text_matches_caption_precision() {
2825-
let text = super::build_cookie_expired_warning_text(999_000, 958_321);
2826-
assert!(text.contains("999.00"));
2827-
assert!(text.contains("958.32"));
2828-
}
2829-
28302676
#[test]
28312677
fn spawn_gate_identifies_supported_messages() {
28322678
assert!(super::should_spawn_message_task("/start"));

0 commit comments

Comments
 (0)