bms_table/fetch/
reqwest.rs

1//! BMS表格数据获取模块
2//!
3//! 这个模块提供了从BMS表格网站获取和解析数据的功能。
4//! 支持从HTML页面提取bmstable字段,解析JSON格式的表格头信息和谱面数据。
5//!
6//! # 主要功能
7//!
8//! - 从HTML页面中提取bmstable字段指向的JSON文件URL
9//! - 解析BMS表格头信息(包含课程、奖杯等元数据)
10//! - 获取和解析谱面数据(包含歌曲信息、下载链接等)
11//! - 完整的BMS表格数据获取流程
12#![cfg(feature = "reqwest")]
13
14use anyhow::{anyhow, Result};
15use serde_json::Value;
16use url::Url;
17
18/// 基于 reqwest 的高层获取函数
19pub async fn fetch_bms_table(web_url: &str) -> Result<crate::BmsTable> {
20    let web_url = Url::parse(web_url)?;
21    let web_response = reqwest::Client::new()
22        .get(web_url.clone())
23        .send()
24        .await
25        .map_err(|e| anyhow!("When fetching web: {e}"))?
26        .text()
27        .await
28        .map_err(|e| anyhow!("When parsing web response: {e}"))?;
29    let (header_url, header_json) = match crate::fetch::get_web_header_json_value(&web_response)? {
30        crate::fetch::HeaderQueryContent::Url(header_url_string) => {
31            let header_url = web_url.join(&header_url_string)?;
32            let header_response = reqwest::Client::new()
33                .get(header_url.clone())
34                .send()
35                .await
36                .map_err(|e| anyhow!("When fetching header: {e}"))?;
37            let header_response_string = header_response
38                .text()
39                .await
40                .map_err(|e| anyhow!("When parsing header response: {e}"))?;
41            let crate::fetch::HeaderQueryContent::Json(header_json) =
42                crate::fetch::get_web_header_json_value(&header_response_string)?
43            else {
44                return Err(anyhow!(
45                    "Cycled header found. web_url: {web_url}, header_url: {header_url_string}"
46                ));
47            };
48            (header_url, header_json)
49        }
50        crate::fetch::HeaderQueryContent::Json(value) => (web_url, value),
51    };
52    let data_url_str = header_json
53        .get("data_url")
54        .ok_or_else(|| anyhow!("\"data_url\" not found in header json!"))?
55        .as_str()
56        .ok_or_else(|| anyhow!("\"data_url\" is not a string!"))?;
57    let data_url = header_url.join(data_url_str)?;
58    let data_response = reqwest::Client::new()
59        .get(data_url)
60        .send()
61        .await
62        .map_err(|e| anyhow!("When fetching web: {e}"))?
63        .text()
64        .await
65        .map_err(|e| anyhow!("When parsing web response: {e}"))?;
66    let data_json: Value = serde_json::from_str(&data_response)?;
67    // 直接使用库内反序列化生成 BmsTable
68    let header: crate::BmsTableHeader = serde_json::from_value(header_json)
69        .map_err(|e| anyhow!("When parsing header json: {e}"))?;
70    let data: crate::BmsTableData =
71        serde_json::from_value(data_json).map_err(|e| anyhow!("When parsing data json: {e}"))?;
72    Ok(crate::BmsTable { header, data })
73}