Skip to main content

BaiduNetDiskClient

Struct BaiduNetDiskClient 

Source
pub struct BaiduNetDiskClient { /* private fields */ }

Implementations§

Source§

impl BaiduNetDiskClient

Source

pub fn builder() -> ClientBuilder

Examples found in repository?
examples/user_info.rs (line 10)
5async fn main() -> Result<(), Box<dyn std::error::Error>> {
6    env_logger::init();
7
8    println!("=== Baidu NetDisk User Info Test ===\n");
9
10    let client = BaiduNetDiskClient::builder()
11        .app_key("your_app_key")
12        .app_secret("your_app_secret")
13        .build()?;
14    info!("Client created successfully");
15
16    client.load_token_from_env()?;
17    info!("Token loaded successfully");
18
19    println!("Getting user info...");
20    let user_info = client.user().get_user_info(Some("v2")).await?;
21
22    println!("\n=== User Information ===");
23    println!("Baidu Name:    {}", user_info.baidu_name);
24    println!("NetDisk Name:  {}", user_info.netdisk_name);
25    println!("Avatar URL:    {}", user_info.avatar_url);
26    println!(
27        "VIP Type:      {}",
28        match user_info.vip_type {
29            0 => "Regular user",
30            1 => "VIP member",
31            2 => "SVIP super member",
32            _ => "Unknown",
33        }
34    );
35    println!("User ID (uk):  {}", user_info.uk);
36
37    Ok(())
38}
More examples
Hide additional examples
examples/category.rs (line 13)
10async fn main() -> Result<(), Box<dyn std::error::Error>> {
11    env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
12
13    let client = BaiduNetDiskClient::builder().build()?;
14    info!("Client created successfully");
15
16    client.load_token_from_env()?;
17    info!("Token loaded successfully");
18
19    let test_dir = "/apps/product";
20
21    println!("=== Baidu NetDisk Category Test ===\n");
22
23    println!("Testing directory: {}\n", test_dir);
24
25    println!("=== Part 1: Global Category Counts (All files) ===");
26    println!("----------------------------------------");
27    test_global_counts(&client).await?;
28
29    println!("\n\n=== Part 2: Category Counts in {} ===", test_dir);
30    println!("----------------------------------------");
31    test_directory_counts(&client, &test_dir).await?;
32
33    println!("\n\n=== Part 3: List Files in Each Category ===");
34    println!("----------------------------------------");
35    test_list_category_files(&client, &test_dir).await?;
36
37    println!("\n\n=== Category Test Completed ===");
38
39    Ok(())
40}
examples/upload_file.rs (line 8)
5async fn main() -> Result<(), Box<dyn std::error::Error>> {
6    env_logger::init();
7
8    let client = BaiduNetDiskClient::builder().build()?;
9    info!("Client created successfully");
10
11    client.load_token_from_env()?;
12    info!("Token loaded successfully");
13
14    let args: Vec<String> = std::env::args().collect();
15
16    if args.len() < 3 {
17        println!("Usage: {} <local_file> <remote_path>", args[0]);
18        println!("Example: {} test.txt /apps/test/test.txt", args[0]);
19        return Ok(());
20    }
21
22    let local_file = &args[1];
23    let remote_path = &args[2];
24
25    println!("=== Baidu NetDisk File Upload (Simple) ===");
26    println!("Local file: {}", local_file);
27    println!("Remote path: {}", remote_path);
28    println!();
29
30    let start_time = std::time::Instant::now();
31
32    let response = client.upload().upload_file(local_file, remote_path).await?;
33
34    println!("File uploaded successfully!");
35    println!("  FS ID: {}", response.fs_id);
36    println!("  Server filename: {:?}", response.server_filename);
37    println!("  Path: {}", response.path);
38    println!("  Size: {} bytes", response.size);
39    println!("  Category: {}", response.category);
40    println!("  MD5: {}", response.md5.unwrap_or_default());
41    println!("  Upload time: {:?}", start_time.elapsed());
42
43    Ok(())
44}
examples/upload_bytes.rs (line 8)
5async fn main() -> Result<(), Box<dyn std::error::Error>> {
6    env_logger::init();
7
8    let client = BaiduNetDiskClient::builder().build()?;
9    info!("Client created successfully");
10
11    client.load_token_from_env()?;
12    info!("Token loaded successfully");
13
14    let args: Vec<String> = std::env::args().collect();
15
16    let remote_path = if args.len() >= 2 {
17        &args[1]
18    } else {
19        "/upload/hello_bytes.txt"
20    };
21
22    println!("=== Baidu NetDisk Bytes Upload (Simple) ===");
23    println!("Remote path: {}", remote_path);
24    println!();
25
26    let test_data = b"Hello from upload_bytes! This is a simple byte array upload test.";
27    println!("Uploading {} bytes of data...", test_data.len());
28
29    let start_time = std::time::Instant::now();
30
31    let response = client.upload().upload_bytes(test_data, remote_path).await?;
32
33    println!("Bytes uploaded successfully!");
34    println!("  FS ID: {}", response.fs_id);
35    println!("  Server filename: {:?}", response.server_filename);
36    println!("  Path: {}", response.path);
37    println!("  Size: {} bytes", response.size);
38    println!("  Category: {}", response.category);
39    println!("  MD5: {}", response.md5.unwrap_or_default());
40    println!("  Upload time: {:?}", start_time.elapsed());
41
42    Ok(())
43}
examples/upload_reader.rs (line 9)
6async fn main() -> Result<(), Box<dyn std::error::Error>> {
7    env_logger::init();
8
9    let client = BaiduNetDiskClient::builder().build()?;
10    info!("Client created successfully");
11
12    client.load_token_from_env()?;
13    info!("Token loaded successfully");
14
15    let args: Vec<String> = std::env::args().collect();
16
17    let local_file = if args.len() >= 2 {
18        &args[1]
19    } else {
20        println!("Usage: {} <local_file> [remote_path]", args[0]);
21        println!("Example: {} test.txt /upload/test.txt", args[0]);
22        return Ok(());
23    };
24
25    let remote_path = if args.len() >= 3 {
26        &args[2]
27    } else {
28        "/upload/test_reader.txt"
29    };
30
31    println!("=== Baidu NetDisk Reader Upload ===");
32    println!("Local file: {}", local_file);
33    println!("Remote path: {}", remote_path);
34    println!();
35
36    let file = std::fs::File::open(local_file)?;
37    let metadata = file.metadata()?;
38    let file_size = metadata.len();
39
40    println!("File size: {} bytes", file_size);
41
42    let mut reader = BufReader::new(file);
43
44    let start_time = std::time::Instant::now();
45
46    let response = client
47        .upload()
48        .upload_reader(&mut reader, file_size, remote_path)
49        .await?;
50
51    println!("File uploaded successfully!");
52    println!("  FS ID: {}", response.fs_id);
53    println!("  Server filename: {:?}", response.server_filename);
54    println!("  Path: {}", response.path);
55    println!("  Size: {} bytes", response.size);
56    println!("  Category: {}", response.category);
57    println!("  MD5: {}", response.md5.unwrap_or_default());
58    println!("  Upload time: {:?}", start_time.elapsed());
59
60    Ok(())
61}
examples/upload_precreate.rs (line 46)
43async fn main() -> Result<(), Box<dyn std::error::Error>> {
44    env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
45
46    let client = BaiduNetDiskClient::builder().build()?;
47    info!("Client created successfully");
48
49    client.load_token_from_env()?;
50    info!("Token loaded successfully");
51
52    let args: Vec<String> = std::env::args().collect();
53
54    if args.len() < 3 {
55        println!("Usage: {} <local_file> <remote_path>", args[0]);
56        println!("Example: {} test.txt /apps/test/test.txt", args[0]);
57        return Ok(());
58    }
59
60    let local_file = &args[1];
61    let remote_path = &args[2];
62
63    println!("=== Baidu NetDisk Preupload Test ===");
64    println!("Local file: {}", local_file);
65    println!("Remote path: {}", remote_path);
66    println!();
67
68    let (file_size, block_list) = get_file_md5blocks(local_file, 4 * 1024 * 1024)?;
69    let file_md5 = calculate_md5(local_file)?;
70
71    println!("File size: {} bytes", file_size);
72    println!("File MD5: {}", file_md5);
73    println!("Block count: {}", block_list.len());
74    println!("Block list: {:?}", block_list);
75    println!();
76
77    let options = PrecreateOptions::new(remote_path, file_size, block_list)
78        .content_md5(&file_md5)
79        .rtype(1);
80
81    println!("Sending precreate request...");
82    match client.upload().precreate(options).await {
83        Ok(response) => {
84            println!("Precreate success!");
85            println!("  Upload ID: {}", response.uploadid);
86            println!("  Path: {:?}", response.path);
87            println!("  Return type: {}", response.return_type);
88            println!("  Block list to upload: {:?}", response.block_list);
89        }
90        Err(e) => {
91            println!("Precreate failed: {}", e);
92        }
93    }
94
95    Ok(())
96}
Source

pub fn authorize(&self) -> &Authorization

Examples found in repository?
examples/auth_flow.rs (line 19)
5async fn main() -> Result<(), Box<dyn std::error::Error>> {
6    env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("debug")).init();
7
8    println!("=== Baidu NetDisk Auth Flow Example ===");
9    println!();
10
11    let client = BaiduNetDiskClient::builder()
12        .timeout(Duration::from_secs(30))
13        .build()?;
14
15    println!("Client created successfully");
16    println!();
17
18    println!("Step 1: Getting device code...");
19    let device_code = client.authorize().get_device_code().await?;
20
21    println!("Device Code Info:");
22    println!("  User Code: {}", device_code.user_code);
23    println!("  Verification URL: {}", device_code.verification_url);
24    println!("  QR Code URL: {}", device_code.qrcode_url);
25    println!("  Interval: {} seconds", device_code.interval);
26    println!(
27        "  Expires in: {} seconds",
28        device_code.expires_at - chrono::Utc::now().timestamp() as u64
29    );
30    println!();
31
32    println!("Please visit the verification URL above and enter the user code to authorize.");
33    println!("Waiting for authorization...");
34    println!();
35
36    let max_attempts = 30;
37    let mut attempts = 0;
38
39    let access_token = loop {
40        attempts += 1;
41
42        if attempts > max_attempts {
43            return Err("Max attempts reached, authorization timeout".into());
44        }
45
46        println!("Attempt {}/{}", attempts, max_attempts);
47
48        match client.authorize().request_access_token(&device_code).await {
49            Ok(Some(token)) => {
50                println!();
51                println!("✅ Authorization successful!");
52                break token;
53            }
54            Ok(None) => {
55                println!("  Authorization pending, waiting...");
56                tokio::time::sleep(Duration::from_secs(device_code.interval as u64)).await;
57                continue;
58            }
59            Err(e) => {
60                println!("  Error: {}", e);
61                tokio::time::sleep(Duration::from_secs(device_code.interval as u64)).await;
62                continue;
63            }
64        }
65    };
66
67    println!();
68    println!("=== Access Token Info ===");
69    println!("Access Token: {}", access_token.access_token);
70    println!("Expires in: {} seconds", access_token.expires_in);
71    println!("Refresh Token: {}", access_token.refresh_token);
72    println!("Scope: {}", access_token.scope);
73    println!("Session Key: {}", access_token.session_key);
74    println!("Session Secret: {}", access_token.session_secret);
75    println!("Acquired At: {}", access_token.acquired_at);
76    println!();
77
78    println!("=== Auth Flow Completed Successfully ===");
79
80    Ok(())
81}
Source

pub fn token_provider(&self) -> &TokenProvider

Examples found in repository?
examples/token_check.rs (line 44)
7async fn main() -> Result<(), Box<dyn std::error::Error>> {
8    // Initialize logger
9    env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("debug")).init();
10
11    println!("=== Token Validation and Refresh Test ===");
12    println!();
13
14    // Create client
15    let client = BaiduNetDiskClient::builder().build()?;
16
17    println!("Client created successfully");
18    println!();
19
20    // Test 1: Load token from environment
21    println!("Test 1: Loading token from environment...");
22    client.load_token_from_env()?;
23
24    let token = client.get_valid_token().await?;
25    println!("Token loaded successfully: {}", token.access_token);
26    println!();
27
28    // Test 2: Check token validity
29    println!("Test 2: Checking token validity...");
30    println!("Token acquired at: {}", token.acquired_at);
31    println!("Token expires in: {} seconds", token.expires_in);
32    println!("Token remaining seconds: {}", token.remaining_seconds());
33    println!("Token is expired: {}", token.is_expired());
34
35    if !token.is_expired() {
36        println!("✓ Token is valid");
37    } else {
38        println!("✗ Token is expired");
39    }
40    println!();
41
42    // Test 3: Test needs_refresh logic
43    println!("Test 3: Testing needs_refresh logic...");
44    let needs_refresh = client.token_provider().needs_refresh()?;
45    println!("Token needs refresh: {}", needs_refresh);
46
47    if !needs_refresh {
48        println!("✓ Token doesn't need refresh");
49    } else {
50        println!("✗ Token needs refresh");
51    }
52    println!();
53
54    // Test 4: Try to get valid token
55    println!("Test 4: Getting valid token...");
56    match client.get_valid_token().await {
57        Ok(valid_token) => {
58            println!("✓ Got valid token: {}", valid_token.access_token);
59            println!(
60                "Token expires in: {} seconds",
61                valid_token.remaining_seconds()
62            );
63        }
64        Err(e) => {
65            println!("✗ Failed to get valid token: {}", e);
66            println!("Note: This is expected if refresh token is invalid/mock");
67        }
68    }
69    println!();
70
71    // Test 5: Test with an expired token
72    println!("Test 5: Testing with expired token...");
73    let expired_token = AccessToken {
74        access_token: "expired_token".to_string(),
75        expires_in: 1, // 1 second
76        refresh_token: "mock_refresh_token".to_string(),
77        scope: "basic netdisk".to_string(),
78        session_key: "".to_string(),
79        session_secret: "".to_string(),
80        acquired_at: SystemTime::now()
81            .duration_since(UNIX_EPOCH)
82            .unwrap_or_default()
83            .as_secs()
84            - 10, // 10 seconds ago
85    };
86
87    client.set_access_token(expired_token.clone())?;
88    println!(
89        "Expired token remaining seconds: {}",
90        expired_token.remaining_seconds()
91    );
92    println!("Expired token is_expired: {}", expired_token.is_expired());
93
94    if expired_token.is_expired() {
95        println!("✓ Expired token correctly identified");
96    } else {
97        println!("✗ Failed to identify expired token");
98    }
99    println!();
100
101    println!("=== Test completed ===");
102    Ok(())
103}
More examples
Hide additional examples
examples/token_refresh.rs (line 34)
7async fn main() -> Result<(), Box<dyn std::error::Error>> {
8    // Initialize logger
9    env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("debug")).init();
10
11    println!("=== Token Refresh Test ===");
12    println!();
13
14    // Create client with auto-refresh enabled
15    let client = BaiduNetDiskClient::builder()
16        .auto_refresh(true)
17        .refresh_ahead_seconds(60)
18        .build()?;
19
20    println!("Client created successfully");
21    println!();
22
23    // Step 1: Load token from environment
24    println!("Step 1: Loading token from environment...");
25    client.load_token_from_env()?;
26    println!("Token loaded successfully");
27
28    let original_token = client.get_valid_token().await?;
29    println!("Original Token: {:?}", original_token);
30    println!();
31
32    // Step 2: Test manual refresh
33    println!("Step 2: Testing manual token refresh...");
34    match client.token_provider().refresh_token().await {
35        Ok(new_token) => {
36            println!("✓ Token refreshed successfully!");
37            println!("  New Access Token: {}", new_token.access_token);
38            println!("  New Refresh Token: {}", new_token.refresh_token);
39            println!("  Expires in: {} seconds", new_token.expires_in);
40            println!();
41
42            // Verify the tokens are different
43            if new_token.access_token != original_token.access_token {
44                println!("✓ Access token changed after refresh");
45            } else {
46                println!("✗ Access token remains the same");
47            }
48
49            // Verify refresh token may have changed
50            if new_token.refresh_token != original_token.refresh_token {
51                println!("✓ Refresh token changed after refresh");
52            } else {
53                println!("Note: Refresh token remains the same (may be expected)");
54            }
55        }
56        Err(e) => {
57            println!("✗ Failed to refresh token: {}", e);
58            println!("Note: This may be due to invalid credentials or network issues");
59        }
60    }
61
62    println!();
63
64    // Step 3: Test auto-refresh with expired token simulation
65    println!("Step 3: Testing auto-refresh behavior...");
66
67    // Create an expired token to test auto-refresh
68    let expired_token = AccessToken {
69        access_token: "expired_access_token".to_string(),
70        expires_in: 60,                                      // 60 seconds
71        refresh_token: original_token.refresh_token.clone(), // Use real refresh token
72        scope: "basic netdisk".to_string(),
73        session_key: "".to_string(),
74        session_secret: "".to_string(),
75        acquired_at: SystemTime::now()
76            .duration_since(UNIX_EPOCH)
77            .unwrap_or_default()
78            .as_secs()
79            - 3600, // 1 hour ago (expired)
80    };
81
82    client.set_access_token(expired_token)?;
83
84    // Now try to get valid token - should trigger auto-refresh
85    match client.get_valid_token().await {
86        Ok(refreshed_token) => {
87            println!("✓ Auto-refresh triggered successfully!");
88            println!("  New Access Token: {}", refreshed_token.access_token);
89            println!(
90                "  Expires in: {} seconds",
91                refreshed_token.remaining_seconds()
92            );
93        }
94        Err(e) => {
95            println!("✗ Auto-refresh failed: {}", e);
96            println!("Note: This may be due to invalid credentials");
97        }
98    }
99
100    println!();
101    println!("=== Refresh test completed ===");
102    Ok(())
103}
Source

pub fn user(&self) -> &UserClient

Examples found in repository?
examples/user_info.rs (line 20)
5async fn main() -> Result<(), Box<dyn std::error::Error>> {
6    env_logger::init();
7
8    println!("=== Baidu NetDisk User Info Test ===\n");
9
10    let client = BaiduNetDiskClient::builder()
11        .app_key("your_app_key")
12        .app_secret("your_app_secret")
13        .build()?;
14    info!("Client created successfully");
15
16    client.load_token_from_env()?;
17    info!("Token loaded successfully");
18
19    println!("Getting user info...");
20    let user_info = client.user().get_user_info(Some("v2")).await?;
21
22    println!("\n=== User Information ===");
23    println!("Baidu Name:    {}", user_info.baidu_name);
24    println!("NetDisk Name:  {}", user_info.netdisk_name);
25    println!("Avatar URL:    {}", user_info.avatar_url);
26    println!(
27        "VIP Type:      {}",
28        match user_info.vip_type {
29            0 => "Regular user",
30            1 => "VIP member",
31            2 => "SVIP super member",
32            _ => "Unknown",
33        }
34    );
35    println!("User ID (uk):  {}", user_info.uk);
36
37    Ok(())
38}
Source

pub fn quota(&self) -> &QuotaClient

Examples found in repository?
examples/quota.rs (line 17)
5async fn main() -> Result<(), Box<dyn std::error::Error>> {
6    env_logger::init();
7
8    println!("=== Baidu NetDisk Quota Test ===\n");
9
10    let client = BaiduNetDiskClient::builder().build()?;
11    info!("Client created successfully");
12
13    client.load_token_from_env()?;
14    info!("Token loaded successfully");
15
16    println!("1. Testing get_quota...");
17    let quota = client.quota().get_quota().await?;
18
19    println!("\n=== Basic Quota Information ===");
20    println!(
21        "Total:    {}",
22        baidu_netdisk_sdk::CapacityInfo::format_bytes(quota.total)
23    );
24    println!(
25        "Used:     {}",
26        baidu_netdisk_sdk::CapacityInfo::format_bytes(quota.used)
27    );
28    println!(
29        "Free:     {}",
30        baidu_netdisk_sdk::CapacityInfo::format_bytes(quota.free)
31    );
32
33    println!("\n2. Testing get_quota_with_expire...");
34    let capacity = client.quota().get_quota_with_expire().await?;
35    println!("\n=== Detailed Capacity Information ===");
36    println!("Total:        {}", capacity.format_total());
37    println!(
38        "Used:         {} ({:.2}%)",
39        capacity.format_used(),
40        capacity.usage_percentage()
41    );
42    println!("Free:         {}", capacity.format_free());
43    println!(
44        "Expired:      {}",
45        if capacity.expire { "Yes" } else { "No" }
46    );
47
48    println!("\n3. Testing get_capacity (check_free only)...");
49    let capacity_free = client.quota().get_capacity(true, false).await?;
50
51    println!("\n=== Capacity with Free Check ===");
52    println!("Total:        {}", capacity_free.format_total());
53    println!("Used:         {}", capacity_free.format_used());
54    println!("Free:         {}", capacity_free.format_free());
55
56    println!("\n4. Testing get_capacity (check_expire only)...");
57    let capacity_expire = client.quota().get_capacity(false, true).await?;
58
59    println!("\n=== Capacity with Expire Check ===");
60    println!("Total:        {}", capacity_expire.format_total());
61    println!("Used:         {}", capacity_expire.format_used());
62    println!(
63        "Expired:      {}",
64        if capacity_expire.expire { "Yes" } else { "No" }
65    );
66
67    println!("\n=== All quota tests completed successfully ===");
68
69    Ok(())
70}
Source

pub fn file(&self) -> &FileClient

Examples found in repository?
examples/category.rs (line 60)
42async fn test_global_counts(client: &BaiduNetDiskClient) -> Result<(), Box<dyn std::error::Error>> {
43    let categories = [
44        (Category::Video, "Video"),
45        (Category::Music, "Music"),
46        (Category::Image, "Image"),
47        (Category::Document, "Document"),
48        (Category::Application, "Application"),
49        (Category::Other, "Other"),
50        (Category::Torrent, "Torrent"),
51    ];
52
53    for (category, name) in categories {
54        let options = CategorySearchOptions::new()
55            .parent_path("/")
56            .recursion(1)
57            .limit(1);
58
59        match client
60            .file()
61            .search_category_files_with_options(&category.as_u32().to_string(), options)
62            .await
63        {
64            Ok((_, total)) => {
65                println!("  {}: {} files", name, total);
66            }
67            Err(e) => {
68                println!("  {}: Error - {}", name, e);
69            }
70        }
71
72        wait_for_rate_limit().await;
73    }
74
75    Ok(())
76}
77
78async fn test_directory_counts(
79    client: &BaiduNetDiskClient,
80    dir: &str,
81) -> Result<(), Box<dyn std::error::Error>> {
82    let categories = [
83        (Category::Video, "Video"),
84        (Category::Music, "Music"),
85        (Category::Image, "Image"),
86        (Category::Document, "Document"),
87        (Category::Application, "Application"),
88        (Category::Other, "Other"),
89        (Category::Torrent, "Torrent"),
90    ];
91
92    for (category, name) in categories {
93        let options = CategorySearchOptions::new()
94            .parent_path(dir)
95            .recursion(1)
96            .limit(1);
97
98        match client
99            .file()
100            .search_category_files_with_options(&category.as_u32().to_string(), options)
101            .await
102        {
103            Ok((_, total)) => {
104                println!("  {}: {} files", name, total);
105            }
106            Err(e) => {
107                println!("  {}: Error - {}", name, e);
108            }
109        }
110
111        wait_for_rate_limit().await;
112    }
113
114    Ok(())
115}
116
117async fn test_list_category_files(
118    client: &BaiduNetDiskClient,
119    dir: &str,
120) -> Result<(), Box<dyn std::error::Error>> {
121    let categories = [
122        (1, "Video"),
123        (2, "Music"),
124        (3, "Image"),
125        (4, "Document"),
126        (5, "Application"),
127        (6, "Other"),
128        (7, "Torrent"),
129    ];
130
131    for (category, name) in categories {
132        println!("\n  [{}] Files:", name);
133
134        let options = CategorySearchOptions::new()
135            .parent_path(dir)
136            .recursion(1)
137            .limit(10);
138
139        match client
140            .file()
141            .search_category_files_with_options(&category.to_string(), options)
142            .await
143        {
144            Ok((files, total)) => {
145                if files.is_empty() {
146                    println!("    (no files)");
147                } else {
148                    for file in files.iter().take(5) {
149                        let size_str = file
150                            .size
151                            .map(|s| format!("{:.2} MB", s as f64 / (1024.0 * 1024.0)))
152                            .unwrap_or_else(|| "N/A".to_string());
153                        println!("    - {} ({})", file.name, size_str);
154                    }
155                    if files.len() > 5 && total > 5 {
156                        println!("    ... and {} more files", total - 5);
157                    }
158                    println!("    Total in this category: {}", total);
159                }
160            }
161            Err(e) => {
162                println!("    Error - {}", e);
163            }
164        }
165
166        wait_for_rate_limit().await;
167    }
168
169    Ok(())
170}
More examples
Hide additional examples
examples/list_all.rs (line 40)
17async fn main() -> Result<(), Box<dyn std::error::Error>> {
18    env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
19
20    let client = BaiduNetDiskClient::builder().build()?;
21    info!("Client created successfully");
22
23    client.load_token_from_env()?;
24    info!("Token loaded successfully");
25
26    let test_dir = "/apps/chapters";
27    let page_size = 10;
28
29    println!("=== Baidu NetDisk ListAll Test ===");
30    println!("Directory: {}", test_dir);
31    println!("Page size: {}\n", page_size);
32
33    let mut start = 0;
34    let mut page_num = 1;
35    let mut total_files = 0;
36    let mut has_more = true;
37
38    while has_more {
39        // 使用简化的 list_all 方法,默认开启递归
40        match client.file().list_all(test_dir, start, page_size).await {
41            Ok(result) => {
42                has_more = result.has_more;
43
44                println!("--- Page {} ---", page_num);
45                println!("Found {} files in this page", result.list.len());
46
47                for file in &result.list {
48                    let size_str = file
49                        .size
50                        .map(|s| format_size(s))
51                        .unwrap_or_else(|| "N/A".to_string());
52                    let is_dir = file.isdir.map(|i| i == 1).unwrap_or(false);
53                    let file_type = if is_dir { "DIR" } else { "FILE" };
54
55                    println!("  [{}] {} ({})", file_type, file.name, size_str);
56                }
57
58                total_files += result.list.len();
59
60                if has_more {
61                    println!("\nPress Enter to continue to page {}...", page_num + 1);
62                    println!("Next cursor: {:?}", result.cursor);
63                    // 使用 cursor 作为下一页的 start,用户无需手动计算
64                    if let Some(cursor) = result.cursor {
65                        start = cursor as i32;
66                    }
67                    let mut input = String::new();
68                    std::io::stdin().read_line(&mut input)?;
69                }
70                page_num += 1;
71            }
72            Err(e) => {
73                println!("Error: {}", e);
74                break;
75            }
76        }
77    }
78
79    println!("\n=== ListAll Test Completed ===");
80    println!("Total files found: {}", total_files);
81
82    Ok(())
83}
examples/search.rs (line 60)
45async fn main() -> Result<(), Box<dyn std::error::Error>> {
46    env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
47
48    let client = BaiduNetDiskClient::builder().build()?;
49    info!("Client created successfully");
50
51    client.load_token_from_env()?;
52    info!("Token loaded successfully");
53
54    println!("=== Baidu NetDisk Search API Test ===");
55    println!();
56
57    // Part 1: Keyword Search (simple)
58    println!("--- Part 1: Keyword Search (simple) ---");
59    let (files, has_more) = client
60        .file()
61        .search_files("test", "/")
62        .await
63        .map_err(|e| format!("Search failed: {}", e))?;
64    print_file_list(&files, &format!("Results (has_more: {}):", has_more));
65    wait_for_rate_limit().await;
66
67    // Part 2: Keyword Search with category filter
68    println!("\n--- Part 2: Keyword Search with Category Filter ---");
69    println!("Searching for '*' in category 4 (Documents):");
70    let options = SearchOptions::new("/").category(4);
71
72    let (files, has_more) = client
73        .file()
74        .search_files_with_options("*", options)
75        .await
76        .map_err(|e| format!("Search failed: {}", e))?;
77    print_file_list(&files, &format!("Results (has_more: {}):", has_more));
78    wait_for_rate_limit().await;
79
80    // Part 3: Keyword Search with recursion
81    println!("\n--- Part 3: Keyword Search with Recursion ---");
82    println!("Recursive search for '*':");
83    let options = SearchOptions::new("/").recursion(true);
84    let (files, has_more) = client
85        .file()
86        .search_files_with_options("*", options)
87        .await
88        .map_err(|e| format!("Search failed: {}", e))?;
89    print_file_list(&files, &format!("Results (has_more: {}):", has_more));
90    wait_for_rate_limit().await;
91
92    // Part 4: Semantic Search (simple)
93    println!("\n--- Part 4: Semantic Search (simple query) ---");
94    println!("Query: \"find text files\"");
95    let files = client
96        .file()
97        .semantic_search("find text files")
98        .await
99        .map_err(|e| format!("Semantic search failed: {}", e))?;
100    print_file_list(&files, "Results:");
101
102    // Part 5: Semantic Search with options
103    println!("\n--- Part 5: Semantic Search with Options ---");
104    println!("Query: \"search for images\" (semantic mode)");
105    let options = SemanticSearchOptions::new().search_type(1);
106    let files = client
107        .file()
108        .semantic_search_with_options("search for images", options)
109        .await
110        .map_err(|e| format!("Semantic search failed: {}", e))?;
111    print_file_list(&files, "Results:");
112
113    // Part 6: Semantic Search with auto mode
114    println!("\n--- Part 6: Semantic Search (auto mode) ---");
115    println!("Query: \"video files\" (auto: uses keyword for short queries)");
116    let options = SemanticSearchOptions::new().search_type(2);
117    let files = client
118        .file()
119        .semantic_search_with_options("video files", options)
120        .await
121        .map_err(|e| format!("Semantic search failed: {}", e))?;
122    print_file_list(&files, "Results:");
123
124    println!("\n=== Test Completed ===");
125
126    Ok(())
127}
examples/download.rs (line 46)
15async fn main() -> Result<(), Box<dyn std::error::Error>> {
16    // Initialize logger
17    env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
18
19    // Create client
20    let client = BaiduNetDiskClient::builder().build()?;
21    info!("Client created successfully");
22
23    // Load token from environment
24    client.load_token_from_env()?;
25    info!("Token loaded successfully");
26
27    println!("=== Baidu NetDisk Download Test ===");
28    println!("Enter the remote file path to download (e.g., /upload/test.txt):");
29
30    let stdin = io::stdin();
31    let mut reader = stdin.lock();
32    let mut input = String::new();
33    reader.read_line(&mut input)?;
34    let remote_path = input.trim();
35
36    if remote_path.is_empty() {
37        eprintln!("Error: File path cannot be empty");
38        return Ok(());
39    }
40
41    // Step 1: Get file info (to obtain fs_id)
42    println!("\n--- Step 1: Get file info (to obtain fs_id) ---");
43    println!("Press Enter to continue...");
44    reader.read_line(&mut String::new())?;
45
46    let file_info = client.file().get_file_info(remote_path).await?;
47    let file_size = file_info.size.unwrap_or(0);
48    let fs_id = file_info.fs_id.ok_or_else(|| "File has no fs_id")?;
49    let file_meta = client.file().get_file_meta(fs_id).await?;
50
51    println!("File Info:");
52    println!("  Name: {}", file_info.name);
53    println!("  Path: {}", file_info.path);
54    println!(
55        "  Size: {} bytes ({:.2} MB)",
56        file_size,
57        file_size as f64 / (1024.0 * 1024.0)
58    );
59    println!("  FS ID: {:?}", file_info.fs_id);
60
61    // Step 2: Single-threaded download (skip for large files > 50MB)
62    println!("\n--- Step 2: Single-threaded download ---");
63    if file_size > 50 * 1024 * 1024 {
64        println!(
65            "File size {} bytes exceeds 50MB, skipping single-threaded download...",
66            file_size
67        );
68    } else {
69        println!("Press Enter to continue...");
70        reader.read_line(&mut String::new())?;
71
72        let single_save_path = format!("./download_single_{}", file_info.name);
73        let start_time = Instant::now();
74
75        match client
76            .download()
77            .download_single(remote_path, &single_save_path)
78            .await
79        {
80            Ok(_) => {
81                let duration = start_time.elapsed();
82                print_download_stats("Single-threaded", file_size, duration);
83                println!("Single-threaded download successful: {}", single_save_path);
84            }
85            Err(e) => eprintln!("Single-threaded download failed: {}", e),
86        }
87    }
88
89    // Step 3: Producer-consumer parallel download (queue-based)
90    println!("\n--- Step 3: Parallel download (Producer-Consumer queue-based) ---");
91    println!("Press Enter to continue...");
92    reader.read_line(&mut String::new())?;
93
94    let parallel_save_path = format!("./download_parallel_{}", file_info.name);
95    let start_time = Instant::now();
96
97    match client
98        .download()
99        .download_parallel_multi_threaded(&file_meta, &parallel_save_path, Some(12))
100        .await
101    {
102        Ok(_) => {
103            let duration = start_time.elapsed();
104            print_download_stats("Parallel (Producer-Consumer)", file_size, duration);
105            println!("Parallel download successful: {}", parallel_save_path);
106        }
107        Err(e) => eprintln!("Parallel download failed: {}", e),
108    }
109
110    // Step 4: Auto download (recommended)
111    println!("\n--- Step 4: Auto download (recommended) ---");
112    println!("Press Enter to continue...");
113    reader.read_line(&mut String::new())?;
114
115    let auto_save_path = format!("./download_auto_{}", file_info.name);
116    let start_time = Instant::now();
117
118    match client
119        .download()
120        .auto_download(remote_path, &auto_save_path)
121        .await
122    {
123        Ok(_) => {
124            let duration = start_time.elapsed();
125            print_download_stats("Auto download", file_size, duration);
126            println!("Auto download successful: {}", auto_save_path);
127        }
128        Err(e) => eprintln!("Auto download failed: {}", e),
129    }
130
131    println!("\n=== Download test completed ===");
132
133    Ok(())
134}
examples/category_list.rs (line 42)
24async fn main() -> Result<(), Box<dyn std::error::Error>> {
25    env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
26
27    let client = BaiduNetDiskClient::builder().build()?;
28    info!("Client created successfully");
29
30    client.load_token_from_env()?;
31    info!("Token loaded successfully");
32
33    let test_dir = "/apps/product";
34    let num_per_page = 5;
35
36    println!("=== Baidu NetDisk Fixed Category List Test ===");
37    println!("Directory: {}", test_dir);
38    println!("Items per page: {}\n", num_per_page);
39
40    println!("--- Part 1: Document List (doclist) ---");
41    match client
42        .file()
43        .list_documents(test_dir, 1, num_per_page)
44        .await
45    {
46        Ok(files) => {
47            println!("Found {} documents", files.len());
48            for file in &files {
49                let size_str = file
50                    .size
51                    .map(|s| format_size(s))
52                    .unwrap_or_else(|| "N/A".to_string());
53                println!("  - {} ({})", file.name, size_str);
54            }
55        }
56        Err(e) => {
57            println!("Error: {}", e);
58        }
59    }
60    wait_for_rate_limit().await;
61
62    println!("\n--- Part 2: Image List (imagelist) ---");
63    match client.file().list_images(test_dir, 1, num_per_page).await {
64        Ok(files) => {
65            println!("Found {} images", files.len());
66            for file in &files {
67                let size_str = file
68                    .size
69                    .map(|s| format_size(s))
70                    .unwrap_or_else(|| "N/A".to_string());
71                println!("  - {} ({})", file.name, size_str);
72            }
73        }
74        Err(e) => {
75            println!("Error: {}", e);
76        }
77    }
78    wait_for_rate_limit().await;
79
80    println!("\n--- Part 3: Video List (videolist) ---");
81    match client.file().list_videos(test_dir, 1, num_per_page).await {
82        Ok(files) => {
83            println!("Found {} videos", files.len());
84            for file in &files {
85                let size_str = file
86                    .size
87                    .map(|s| format_size(s))
88                    .unwrap_or_else(|| "N/A".to_string());
89                println!("  - {} ({})", file.name, size_str);
90            }
91        }
92        Err(e) => {
93            println!("Error: {}", e);
94        }
95    }
96    wait_for_rate_limit().await;
97
98    println!("\n--- Part 4: BT List (btlist) ---");
99    match client.file().list_torrents(test_dir, 1, num_per_page).await {
100        Ok(files) => {
101            println!("Found {} torrent files", files.len());
102            for file in &files {
103                let size_str = file
104                    .size
105                    .map(|s| format_size(s))
106                    .unwrap_or_else(|| "N/A".to_string());
107                println!("  - {} ({})", file.name, size_str);
108            }
109        }
110        Err(e) => {
111            println!("Error: {}", e);
112        }
113    }
114    wait_for_rate_limit().await;
115
116    println!("\n=== Test with Options (recursion=1) ===");
117    println!("Directory: {}\n", test_dir);
118
119    println!("--- Document List with recursion ---");
120    let options = DocumentListOptions::new(test_dir)
121        .recursion(1)
122        .num(num_per_page);
123    match client.file().list_documents_with_options(options).await {
124        Ok(files) => {
125            println!("Found {} documents", files.len());
126            for file in &files {
127                let size_str = file
128                    .size
129                    .map(|s| format_size(s))
130                    .unwrap_or_else(|| "N/A".to_string());
131                println!("  - {} ({})", file.name, size_str);
132            }
133        }
134        Err(e) => {
135            println!("Error: {}", e);
136        }
137    }
138    wait_for_rate_limit().await;
139
140    println!("\n--- Image List with recursion ---");
141    let options = ImageListOptions::new(test_dir)
142        .recursion(1)
143        .num(num_per_page);
144    match client.file().list_images_with_options(options).await {
145        Ok(files) => {
146            println!("Found {} images", files.len());
147            for file in &files {
148                let size_str = file
149                    .size
150                    .map(|s| format_size(s))
151                    .unwrap_or_else(|| "N/A".to_string());
152                println!("  - {} ({})", file.name, size_str);
153            }
154        }
155        Err(e) => {
156            println!("Error: {}", e);
157        }
158    }
159    wait_for_rate_limit().await;
160
161    println!("\n--- Video List with recursion ---");
162    let options = VideoListOptions::new(test_dir)
163        .recursion(1)
164        .num(num_per_page);
165    match client.file().list_videos_with_options(options).await {
166        Ok(files) => {
167            println!("Found {} videos", files.len());
168            for file in &files {
169                let size_str = file
170                    .size
171                    .map(|s| format_size(s))
172                    .unwrap_or_else(|| "N/A".to_string());
173                println!("  - {} ({})", file.name, size_str);
174            }
175        }
176        Err(e) => {
177            println!("Error: {}", e);
178        }
179    }
180    wait_for_rate_limit().await;
181
182    println!("\n--- BT List with recursion ---");
183    let options = BtListOptions::new(test_dir).recursion(1).num(num_per_page);
184    match client.file().list_torrents_with_options(options).await {
185        Ok(files) => {
186            println!("Found {} torrent files", files.len());
187            for file in &files {
188                let size_str = file
189                    .size
190                    .map(|s| format_size(s))
191                    .unwrap_or_else(|| "N/A".to_string());
192                println!("  - {} ({})", file.name, size_str);
193            }
194        }
195        Err(e) => {
196            println!("Error: {}", e);
197        }
198    }
199
200    println!("\n=== Test Completed ===");
201
202    Ok(())
203}
examples/download_compare.rs (line 44)
8async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
9    env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
10
11    let client = BaiduNetDiskClient::builder().build()?;
12    info!("Client created successfully");
13
14    client.load_token_from_env()?;
15    info!("Token loaded successfully");
16
17    println!("=== Baidu NetDisk Download Comparison Test ===");
18    println!();
19    println!(
20        "Enter the number of threads/concurrency to use (recommended: match your CPU core count)"
21    );
22    println!("Example: 4 for 4 cores, 8 for 8 cores, etc.");
23    let mut input = String::new();
24    std::io::stdin().read_line(&mut input)?;
25    let thread_num: usize = input.trim().parse().unwrap_or(4);
26    let concurrency = thread_num * 3;
27    println!();
28    println!("Thread count: {}", thread_num);
29    println!("Concurrency: {}", concurrency);
30    println!();
31
32    println!("=== Method 1: Streaming (Futures/Concurrency) ===");
33    println!("Enter the remote file path to download:");
34    let mut input = String::new();
35    std::io::stdin().read_line(&mut input)?;
36    let remote_path_streaming = input.trim();
37
38    if remote_path_streaming.is_empty() {
39        eprintln!("Error: File path cannot be empty");
40        return Ok(());
41    }
42
43    println!("\n--- Step 1: Get file info for Streaming ---");
44    let file_info_streaming = client.file().get_file_info(remote_path_streaming).await?;
45    let file_size_streaming = file_info_streaming.size.unwrap_or(0);
46    let fs_id_streaming = file_info_streaming.fs_id.ok_or("File has no fs_id")?;
47    let file_meta_streaming = client.file().get_file_meta(fs_id_streaming).await?;
48
49    println!("File: {}", file_info_streaming.name);
50    println!(
51        "Size: {} bytes ({:.2} MB)",
52        file_size_streaming,
53        file_size_streaming as f64 / (1024.0 * 1024.0)
54    );
55    let total_chunks_streaming = (file_size_streaming + CHUNK_SIZE - 1) / CHUNK_SIZE;
56    println!(
57        "Chunks: {} ({} bytes each)",
58        total_chunks_streaming, CHUNK_SIZE
59    );
60    println!();
61
62    println!("Press Enter to start Streaming download...");
63    std::io::stdin().read_line(&mut String::new())?;
64
65    let streaming_save_path = format!("./download_streaming_{}", file_info_streaming.name);
66    let start_streaming = std::time::Instant::now();
67
68    client
69        .download()
70        .download_streaming_with_meta(
71            &file_meta_streaming,
72            Path::new(&streaming_save_path),
73            concurrency,
74        )
75        .await?;
76
77    let duration_streaming = start_streaming.elapsed();
78    let streaming_mb = file_size_streaming as f64 / (1024.0 * 1024.0);
79    let streaming_sec = duration_streaming.as_secs_f64();
80    let streaming_speed = streaming_mb / streaming_sec;
81
82    println!();
83    println!("=== Method 2: Parallel (Multi-thread) ===");
84    println!("Enter the remote file path to download:");
85    let mut input = String::new();
86    std::io::stdin().read_line(&mut input)?;
87    let remote_path_parallel = input.trim();
88
89    if remote_path_parallel.is_empty() {
90        eprintln!("Error: File path cannot be empty");
91        return Ok(());
92    }
93
94    println!("\n--- Step 1: Get file info for Parallel ---");
95    let file_info_parallel = client.file().get_file_info(remote_path_parallel).await?;
96    let file_size_parallel = file_info_parallel.size.unwrap_or(0);
97    let fs_id_parallel = file_info_parallel.fs_id.ok_or("File has no fs_id")?;
98    let file_meta_parallel = client.file().get_file_meta(fs_id_parallel).await?;
99
100    println!("File: {}", file_info_parallel.name);
101    println!(
102        "Size: {} bytes ({:.2} MB)",
103        file_size_parallel,
104        file_size_parallel as f64 / (1024.0 * 1024.0)
105    );
106    let total_chunks_parallel = (file_size_parallel + CHUNK_SIZE - 1) / CHUNK_SIZE;
107    println!(
108        "Chunks: {} ({} bytes each)",
109        total_chunks_parallel, CHUNK_SIZE
110    );
111    println!();
112
113    println!("Press Enter to start Parallel download...");
114    std::io::stdin().read_line(&mut String::new())?;
115
116    let parallel_save_path = format!("./download_parallel_{}", file_info_parallel.name);
117    let start_parallel = std::time::Instant::now();
118
119    client
120        .download()
121        .download_parallel_multi_threaded(
122            &file_meta_parallel,
123            Path::new(&parallel_save_path),
124            Some(thread_num),
125        )
126        .await?;
127
128    let duration_parallel = start_parallel.elapsed();
129    let parallel_mb = file_size_parallel as f64 / (1024.0 * 1024.0);
130    let parallel_sec = duration_parallel.as_secs_f64();
131    let parallel_speed = parallel_mb / parallel_sec;
132
133    println!();
134    println!("╔══════════════════════════════════════════════════════════════════════════╗");
135    println!("║                        DOWNLOAD COMPARISON RESULTS                         ║");
136    println!("╠══════════════════════════════════════════════════════════════════════════╣");
137    println!(
138        "║  Threads: {}  │  Concurrency (Streaming): {}  │                  ║",
139        thread_num, concurrency
140    );
141    println!("╠══════════════════════════════════════════════════════════════════════════╣");
142    println!("║  Method                      │ Time       │ Speed       │ File           ║");
143    println!("╠══════════════════════════════════════════════════════════════════════════╣");
144    println!(
145        "║  Streaming (Futures)         │ {:>8.2}s  │ {:>8.2} MB/s │ {:.15} ║",
146        streaming_sec, streaming_speed, file_info_streaming.name
147    );
148    println!(
149        "║  Parallel (Multi-thread)     │ {:>8.2}s  │ {:>8.2} MB/s │ {:.15} ║",
150        parallel_sec, parallel_speed, file_info_parallel.name
151    );
152    println!("╠══════════════════════════════════════════════════════════════════════════╣");
153    let speedup = if streaming_sec < parallel_sec {
154        parallel_sec / streaming_sec
155    } else {
156        streaming_sec / parallel_sec
157    };
158    let faster = if streaming_sec < parallel_sec {
159        "Streaming"
160    } else {
161        "Parallel"
162    };
163    println!(
164        "║  Faster: {} ({:.2}x)                                              ║",
165        faster, speedup
166    );
167    println!("╠══════════════════════════════════════════════════════════════════════════╣");
168    println!("║  Note: Parallel mode works best with 6+ cores. On 4 cores, Streaming may  ║");
169    println!("║        be 2x faster. Test with your actual core count for best results!   ║");
170    println!("╚══════════════════════════════════════════════════════════════════════════╝");
171
172    println!();
173    println!("Output files:");
174    println!("  Parallel:   {}", parallel_save_path);
175    println!("  Streaming:  {}", streaming_save_path);
176
177    Ok(())
178}
Source

pub fn download(&self) -> &DownloadClient

Examples found in repository?
examples/download.rs (line 76)
15async fn main() -> Result<(), Box<dyn std::error::Error>> {
16    // Initialize logger
17    env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
18
19    // Create client
20    let client = BaiduNetDiskClient::builder().build()?;
21    info!("Client created successfully");
22
23    // Load token from environment
24    client.load_token_from_env()?;
25    info!("Token loaded successfully");
26
27    println!("=== Baidu NetDisk Download Test ===");
28    println!("Enter the remote file path to download (e.g., /upload/test.txt):");
29
30    let stdin = io::stdin();
31    let mut reader = stdin.lock();
32    let mut input = String::new();
33    reader.read_line(&mut input)?;
34    let remote_path = input.trim();
35
36    if remote_path.is_empty() {
37        eprintln!("Error: File path cannot be empty");
38        return Ok(());
39    }
40
41    // Step 1: Get file info (to obtain fs_id)
42    println!("\n--- Step 1: Get file info (to obtain fs_id) ---");
43    println!("Press Enter to continue...");
44    reader.read_line(&mut String::new())?;
45
46    let file_info = client.file().get_file_info(remote_path).await?;
47    let file_size = file_info.size.unwrap_or(0);
48    let fs_id = file_info.fs_id.ok_or_else(|| "File has no fs_id")?;
49    let file_meta = client.file().get_file_meta(fs_id).await?;
50
51    println!("File Info:");
52    println!("  Name: {}", file_info.name);
53    println!("  Path: {}", file_info.path);
54    println!(
55        "  Size: {} bytes ({:.2} MB)",
56        file_size,
57        file_size as f64 / (1024.0 * 1024.0)
58    );
59    println!("  FS ID: {:?}", file_info.fs_id);
60
61    // Step 2: Single-threaded download (skip for large files > 50MB)
62    println!("\n--- Step 2: Single-threaded download ---");
63    if file_size > 50 * 1024 * 1024 {
64        println!(
65            "File size {} bytes exceeds 50MB, skipping single-threaded download...",
66            file_size
67        );
68    } else {
69        println!("Press Enter to continue...");
70        reader.read_line(&mut String::new())?;
71
72        let single_save_path = format!("./download_single_{}", file_info.name);
73        let start_time = Instant::now();
74
75        match client
76            .download()
77            .download_single(remote_path, &single_save_path)
78            .await
79        {
80            Ok(_) => {
81                let duration = start_time.elapsed();
82                print_download_stats("Single-threaded", file_size, duration);
83                println!("Single-threaded download successful: {}", single_save_path);
84            }
85            Err(e) => eprintln!("Single-threaded download failed: {}", e),
86        }
87    }
88
89    // Step 3: Producer-consumer parallel download (queue-based)
90    println!("\n--- Step 3: Parallel download (Producer-Consumer queue-based) ---");
91    println!("Press Enter to continue...");
92    reader.read_line(&mut String::new())?;
93
94    let parallel_save_path = format!("./download_parallel_{}", file_info.name);
95    let start_time = Instant::now();
96
97    match client
98        .download()
99        .download_parallel_multi_threaded(&file_meta, &parallel_save_path, Some(12))
100        .await
101    {
102        Ok(_) => {
103            let duration = start_time.elapsed();
104            print_download_stats("Parallel (Producer-Consumer)", file_size, duration);
105            println!("Parallel download successful: {}", parallel_save_path);
106        }
107        Err(e) => eprintln!("Parallel download failed: {}", e),
108    }
109
110    // Step 4: Auto download (recommended)
111    println!("\n--- Step 4: Auto download (recommended) ---");
112    println!("Press Enter to continue...");
113    reader.read_line(&mut String::new())?;
114
115    let auto_save_path = format!("./download_auto_{}", file_info.name);
116    let start_time = Instant::now();
117
118    match client
119        .download()
120        .auto_download(remote_path, &auto_save_path)
121        .await
122    {
123        Ok(_) => {
124            let duration = start_time.elapsed();
125            print_download_stats("Auto download", file_size, duration);
126            println!("Auto download successful: {}", auto_save_path);
127        }
128        Err(e) => eprintln!("Auto download failed: {}", e),
129    }
130
131    println!("\n=== Download test completed ===");
132
133    Ok(())
134}
More examples
Hide additional examples
examples/download_compare.rs (line 69)
8async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
9    env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
10
11    let client = BaiduNetDiskClient::builder().build()?;
12    info!("Client created successfully");
13
14    client.load_token_from_env()?;
15    info!("Token loaded successfully");
16
17    println!("=== Baidu NetDisk Download Comparison Test ===");
18    println!();
19    println!(
20        "Enter the number of threads/concurrency to use (recommended: match your CPU core count)"
21    );
22    println!("Example: 4 for 4 cores, 8 for 8 cores, etc.");
23    let mut input = String::new();
24    std::io::stdin().read_line(&mut input)?;
25    let thread_num: usize = input.trim().parse().unwrap_or(4);
26    let concurrency = thread_num * 3;
27    println!();
28    println!("Thread count: {}", thread_num);
29    println!("Concurrency: {}", concurrency);
30    println!();
31
32    println!("=== Method 1: Streaming (Futures/Concurrency) ===");
33    println!("Enter the remote file path to download:");
34    let mut input = String::new();
35    std::io::stdin().read_line(&mut input)?;
36    let remote_path_streaming = input.trim();
37
38    if remote_path_streaming.is_empty() {
39        eprintln!("Error: File path cannot be empty");
40        return Ok(());
41    }
42
43    println!("\n--- Step 1: Get file info for Streaming ---");
44    let file_info_streaming = client.file().get_file_info(remote_path_streaming).await?;
45    let file_size_streaming = file_info_streaming.size.unwrap_or(0);
46    let fs_id_streaming = file_info_streaming.fs_id.ok_or("File has no fs_id")?;
47    let file_meta_streaming = client.file().get_file_meta(fs_id_streaming).await?;
48
49    println!("File: {}", file_info_streaming.name);
50    println!(
51        "Size: {} bytes ({:.2} MB)",
52        file_size_streaming,
53        file_size_streaming as f64 / (1024.0 * 1024.0)
54    );
55    let total_chunks_streaming = (file_size_streaming + CHUNK_SIZE - 1) / CHUNK_SIZE;
56    println!(
57        "Chunks: {} ({} bytes each)",
58        total_chunks_streaming, CHUNK_SIZE
59    );
60    println!();
61
62    println!("Press Enter to start Streaming download...");
63    std::io::stdin().read_line(&mut String::new())?;
64
65    let streaming_save_path = format!("./download_streaming_{}", file_info_streaming.name);
66    let start_streaming = std::time::Instant::now();
67
68    client
69        .download()
70        .download_streaming_with_meta(
71            &file_meta_streaming,
72            Path::new(&streaming_save_path),
73            concurrency,
74        )
75        .await?;
76
77    let duration_streaming = start_streaming.elapsed();
78    let streaming_mb = file_size_streaming as f64 / (1024.0 * 1024.0);
79    let streaming_sec = duration_streaming.as_secs_f64();
80    let streaming_speed = streaming_mb / streaming_sec;
81
82    println!();
83    println!("=== Method 2: Parallel (Multi-thread) ===");
84    println!("Enter the remote file path to download:");
85    let mut input = String::new();
86    std::io::stdin().read_line(&mut input)?;
87    let remote_path_parallel = input.trim();
88
89    if remote_path_parallel.is_empty() {
90        eprintln!("Error: File path cannot be empty");
91        return Ok(());
92    }
93
94    println!("\n--- Step 1: Get file info for Parallel ---");
95    let file_info_parallel = client.file().get_file_info(remote_path_parallel).await?;
96    let file_size_parallel = file_info_parallel.size.unwrap_or(0);
97    let fs_id_parallel = file_info_parallel.fs_id.ok_or("File has no fs_id")?;
98    let file_meta_parallel = client.file().get_file_meta(fs_id_parallel).await?;
99
100    println!("File: {}", file_info_parallel.name);
101    println!(
102        "Size: {} bytes ({:.2} MB)",
103        file_size_parallel,
104        file_size_parallel as f64 / (1024.0 * 1024.0)
105    );
106    let total_chunks_parallel = (file_size_parallel + CHUNK_SIZE - 1) / CHUNK_SIZE;
107    println!(
108        "Chunks: {} ({} bytes each)",
109        total_chunks_parallel, CHUNK_SIZE
110    );
111    println!();
112
113    println!("Press Enter to start Parallel download...");
114    std::io::stdin().read_line(&mut String::new())?;
115
116    let parallel_save_path = format!("./download_parallel_{}", file_info_parallel.name);
117    let start_parallel = std::time::Instant::now();
118
119    client
120        .download()
121        .download_parallel_multi_threaded(
122            &file_meta_parallel,
123            Path::new(&parallel_save_path),
124            Some(thread_num),
125        )
126        .await?;
127
128    let duration_parallel = start_parallel.elapsed();
129    let parallel_mb = file_size_parallel as f64 / (1024.0 * 1024.0);
130    let parallel_sec = duration_parallel.as_secs_f64();
131    let parallel_speed = parallel_mb / parallel_sec;
132
133    println!();
134    println!("╔══════════════════════════════════════════════════════════════════════════╗");
135    println!("║                        DOWNLOAD COMPARISON RESULTS                         ║");
136    println!("╠══════════════════════════════════════════════════════════════════════════╣");
137    println!(
138        "║  Threads: {}  │  Concurrency (Streaming): {}  │                  ║",
139        thread_num, concurrency
140    );
141    println!("╠══════════════════════════════════════════════════════════════════════════╣");
142    println!("║  Method                      │ Time       │ Speed       │ File           ║");
143    println!("╠══════════════════════════════════════════════════════════════════════════╣");
144    println!(
145        "║  Streaming (Futures)         │ {:>8.2}s  │ {:>8.2} MB/s │ {:.15} ║",
146        streaming_sec, streaming_speed, file_info_streaming.name
147    );
148    println!(
149        "║  Parallel (Multi-thread)     │ {:>8.2}s  │ {:>8.2} MB/s │ {:.15} ║",
150        parallel_sec, parallel_speed, file_info_parallel.name
151    );
152    println!("╠══════════════════════════════════════════════════════════════════════════╣");
153    let speedup = if streaming_sec < parallel_sec {
154        parallel_sec / streaming_sec
155    } else {
156        streaming_sec / parallel_sec
157    };
158    let faster = if streaming_sec < parallel_sec {
159        "Streaming"
160    } else {
161        "Parallel"
162    };
163    println!(
164        "║  Faster: {} ({:.2}x)                                              ║",
165        faster, speedup
166    );
167    println!("╠══════════════════════════════════════════════════════════════════════════╣");
168    println!("║  Note: Parallel mode works best with 6+ cores. On 4 cores, Streaming may  ║");
169    println!("║        be 2x faster. Test with your actual core count for best results!   ║");
170    println!("╚══════════════════════════════════════════════════════════════════════════╝");
171
172    println!();
173    println!("Output files:");
174    println!("  Parallel:   {}", parallel_save_path);
175    println!("  Streaming:  {}", streaming_save_path);
176
177    Ok(())
178}
Source

pub fn upload(&self) -> &UploadClient

Examples found in repository?
examples/upload_file.rs (line 32)
5async fn main() -> Result<(), Box<dyn std::error::Error>> {
6    env_logger::init();
7
8    let client = BaiduNetDiskClient::builder().build()?;
9    info!("Client created successfully");
10
11    client.load_token_from_env()?;
12    info!("Token loaded successfully");
13
14    let args: Vec<String> = std::env::args().collect();
15
16    if args.len() < 3 {
17        println!("Usage: {} <local_file> <remote_path>", args[0]);
18        println!("Example: {} test.txt /apps/test/test.txt", args[0]);
19        return Ok(());
20    }
21
22    let local_file = &args[1];
23    let remote_path = &args[2];
24
25    println!("=== Baidu NetDisk File Upload (Simple) ===");
26    println!("Local file: {}", local_file);
27    println!("Remote path: {}", remote_path);
28    println!();
29
30    let start_time = std::time::Instant::now();
31
32    let response = client.upload().upload_file(local_file, remote_path).await?;
33
34    println!("File uploaded successfully!");
35    println!("  FS ID: {}", response.fs_id);
36    println!("  Server filename: {:?}", response.server_filename);
37    println!("  Path: {}", response.path);
38    println!("  Size: {} bytes", response.size);
39    println!("  Category: {}", response.category);
40    println!("  MD5: {}", response.md5.unwrap_or_default());
41    println!("  Upload time: {:?}", start_time.elapsed());
42
43    Ok(())
44}
More examples
Hide additional examples
examples/upload_bytes.rs (line 31)
5async fn main() -> Result<(), Box<dyn std::error::Error>> {
6    env_logger::init();
7
8    let client = BaiduNetDiskClient::builder().build()?;
9    info!("Client created successfully");
10
11    client.load_token_from_env()?;
12    info!("Token loaded successfully");
13
14    let args: Vec<String> = std::env::args().collect();
15
16    let remote_path = if args.len() >= 2 {
17        &args[1]
18    } else {
19        "/upload/hello_bytes.txt"
20    };
21
22    println!("=== Baidu NetDisk Bytes Upload (Simple) ===");
23    println!("Remote path: {}", remote_path);
24    println!();
25
26    let test_data = b"Hello from upload_bytes! This is a simple byte array upload test.";
27    println!("Uploading {} bytes of data...", test_data.len());
28
29    let start_time = std::time::Instant::now();
30
31    let response = client.upload().upload_bytes(test_data, remote_path).await?;
32
33    println!("Bytes uploaded successfully!");
34    println!("  FS ID: {}", response.fs_id);
35    println!("  Server filename: {:?}", response.server_filename);
36    println!("  Path: {}", response.path);
37    println!("  Size: {} bytes", response.size);
38    println!("  Category: {}", response.category);
39    println!("  MD5: {}", response.md5.unwrap_or_default());
40    println!("  Upload time: {:?}", start_time.elapsed());
41
42    Ok(())
43}
examples/upload_reader.rs (line 47)
6async fn main() -> Result<(), Box<dyn std::error::Error>> {
7    env_logger::init();
8
9    let client = BaiduNetDiskClient::builder().build()?;
10    info!("Client created successfully");
11
12    client.load_token_from_env()?;
13    info!("Token loaded successfully");
14
15    let args: Vec<String> = std::env::args().collect();
16
17    let local_file = if args.len() >= 2 {
18        &args[1]
19    } else {
20        println!("Usage: {} <local_file> [remote_path]", args[0]);
21        println!("Example: {} test.txt /upload/test.txt", args[0]);
22        return Ok(());
23    };
24
25    let remote_path = if args.len() >= 3 {
26        &args[2]
27    } else {
28        "/upload/test_reader.txt"
29    };
30
31    println!("=== Baidu NetDisk Reader Upload ===");
32    println!("Local file: {}", local_file);
33    println!("Remote path: {}", remote_path);
34    println!();
35
36    let file = std::fs::File::open(local_file)?;
37    let metadata = file.metadata()?;
38    let file_size = metadata.len();
39
40    println!("File size: {} bytes", file_size);
41
42    let mut reader = BufReader::new(file);
43
44    let start_time = std::time::Instant::now();
45
46    let response = client
47        .upload()
48        .upload_reader(&mut reader, file_size, remote_path)
49        .await?;
50
51    println!("File uploaded successfully!");
52    println!("  FS ID: {}", response.fs_id);
53    println!("  Server filename: {:?}", response.server_filename);
54    println!("  Path: {}", response.path);
55    println!("  Size: {} bytes", response.size);
56    println!("  Category: {}", response.category);
57    println!("  MD5: {}", response.md5.unwrap_or_default());
58    println!("  Upload time: {:?}", start_time.elapsed());
59
60    Ok(())
61}
examples/upload_precreate.rs (line 82)
43async fn main() -> Result<(), Box<dyn std::error::Error>> {
44    env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
45
46    let client = BaiduNetDiskClient::builder().build()?;
47    info!("Client created successfully");
48
49    client.load_token_from_env()?;
50    info!("Token loaded successfully");
51
52    let args: Vec<String> = std::env::args().collect();
53
54    if args.len() < 3 {
55        println!("Usage: {} <local_file> <remote_path>", args[0]);
56        println!("Example: {} test.txt /apps/test/test.txt", args[0]);
57        return Ok(());
58    }
59
60    let local_file = &args[1];
61    let remote_path = &args[2];
62
63    println!("=== Baidu NetDisk Preupload Test ===");
64    println!("Local file: {}", local_file);
65    println!("Remote path: {}", remote_path);
66    println!();
67
68    let (file_size, block_list) = get_file_md5blocks(local_file, 4 * 1024 * 1024)?;
69    let file_md5 = calculate_md5(local_file)?;
70
71    println!("File size: {} bytes", file_size);
72    println!("File MD5: {}", file_md5);
73    println!("Block count: {}", block_list.len());
74    println!("Block list: {:?}", block_list);
75    println!();
76
77    let options = PrecreateOptions::new(remote_path, file_size, block_list)
78        .content_md5(&file_md5)
79        .rtype(1);
80
81    println!("Sending precreate request...");
82    match client.upload().precreate(options).await {
83        Ok(response) => {
84            println!("Precreate success!");
85            println!("  Upload ID: {}", response.uploadid);
86            println!("  Path: {:?}", response.path);
87            println!("  Return type: {}", response.return_type);
88            println!("  Block list to upload: {:?}", response.block_list);
89        }
90        Err(e) => {
91            println!("Precreate failed: {}", e);
92        }
93    }
94
95    Ok(())
96}
examples/upload_file_options.rs (line 55)
6async fn main() -> Result<(), Box<dyn std::error::Error>> {
7    env_logger::init();
8
9    let client = BaiduNetDiskClient::builder().build()?;
10    info!("Client created successfully");
11
12    client.load_token_from_env()?;
13    info!("Token loaded successfully");
14
15    let args: Vec<String> = std::env::args().collect();
16
17    if args.len() < 3 {
18        println!(
19            "Usage: {} <local_file> <remote_path> [chunk_size] [concurrency]",
20            args[0]
21        );
22        println!("Example: {} test.mp4 /upload/video.mp4 8388608 20", args[0]);
23        println!("  - chunk_size: bytes per chunk (default: 4194304 = 4MB)");
24        println!("  - concurrency: parallel uploads (default: 10)");
25        return Ok(());
26    }
27
28    let local_file = &args[1];
29    let remote_path = &args[2];
30
31    let chunk_size: usize = args
32        .get(3)
33        .and_then(|s| s.parse().ok())
34        .unwrap_or(4 * 1024 * 1024);
35    let concurrency: usize = args.get(4).and_then(|s| s.parse().ok()).unwrap_or(10);
36
37    let options = SimpleUploadOptions::default()
38        .chunk_size(chunk_size)
39        .max_concurrency(concurrency);
40
41    println!("=== Baidu NetDisk File Upload (Custom Options) ===");
42    println!("Local file: {}", local_file);
43    println!("Remote path: {}", remote_path);
44    println!(
45        "Chunk size: {} bytes ({:.2} MB)",
46        chunk_size,
47        chunk_size as f64 / 1024.0 / 1024.0
48    );
49    println!("Concurrency: {}", concurrency);
50    println!();
51
52    let start_time = std::time::Instant::now();
53
54    let response = client
55        .upload()
56        .upload_file_with_options(local_file, remote_path, options)
57        .await?;
58
59    println!("File uploaded successfully!");
60    println!("  FS ID: {}", response.fs_id);
61    println!("  Path: {}", response.path);
62    println!("  Size: {} bytes", response.size);
63    println!("  Category: {}", response.category);
64    println!("  MD5: {}", response.md5.unwrap_or_default());
65    println!("  Upload time: {:?}", start_time.elapsed());
66
67    Ok(())
68}
Source

pub fn playlist(&self) -> &PlaylistClient

Examples found in repository?
examples/playlist.rs (line 26)
7async fn main() -> Result<(), Box<dyn std::error::Error>> {
8    // Initialize logger
9    env_logger::init();
10
11    println!("=== Baidu NetDisk Playlist Test ===\n");
12
13    // Create client - will automatically load from .env file
14    let client = BaiduNetDiskClient::builder().build()?;
15    info!("Client created successfully");
16
17    // Load token from environment variables
18    client.load_token_from_env()?;
19    info!("Token loaded successfully");
20
21    // === Part 1: Get Playlist List ===
22    println!("=== Part 1: Get Playlist List ===");
23    println!("This will fetch all playlists from your Baidu NetDisk");
24    wait_for_enter();
25
26    let playlists = match client.playlist().get_playlist_list().await {
27        Ok(pl) => {
28            println!("✓ Successfully retrieved playlist list!");
29            println!(
30                "  Has more: {}",
31                if pl.has_more == 1 { "Yes" } else { "No" }
32            );
33            println!("  Found {} playlist(s):", pl.list.len());
34            for (idx, playlist) in pl.list.iter().enumerate() {
35                println!("    {}. {}", idx + 1, playlist.name);
36                println!("       mb_id: {}", playlist.mb_id);
37                println!("       file_count: {}", playlist.file_count);
38                println!("       btype: {}", playlist.btype);
39                println!("       bstype: {}", playlist.bstype);
40                println!("       ctime: {}", playlist.ctime);
41                println!("       mtime: {}", playlist.mtime);
42            }
43            Some(pl)
44        }
45        Err(e) => {
46            println!("! Failed to get playlist list: {}", e);
47            None
48        }
49    };
50
51    // === Part 2: Get Playlist File List ===
52    println!("\n=== Part 2: Get Playlist File List ===");
53    println!("mb_id is the unique identifier for a playlist (numeric).");
54    if playlists.is_some() && !playlists.as_ref().unwrap().list.is_empty() {
55        println!("Available playlists, please select one's mb_id:");
56        for (idx, playlist) in playlists.as_ref().unwrap().list.iter().enumerate() {
57            println!(
58                "  {}. {} - mb_id: {}",
59                idx + 1,
60                playlist.name,
61                playlist.mb_id
62            );
63        }
64    }
65    println!("Please enter mb_id, or press Enter to skip:");
66    let mut input = String::new();
67    std::io::stdin().read_line(&mut input)?;
68    let input_trimmed = input.trim();
69
70    let playlist_mb_id = if input_trimmed.is_empty() && playlists.is_some() {
71        // If user just pressed enter and we have playlists, use the first one
72        println!("  No input provided, using the first playlist...");
73        playlists
74            .as_ref()
75            .and_then(|pl| pl.list.first())
76            .map(|p| p.mb_id)
77    } else {
78        // Try to parse as number
79        match input_trimmed.parse::<u64>() {
80            Ok(mb_id) => Some(mb_id),
81            Err(_) => {
82                println!("  Invalid input, please enter a valid mb_id");
83                None
84            }
85        }
86    };
87
88    let playlist_files = if let Some(mb_id) = playlist_mb_id {
89        println!("\nGetting files from playlist with mb_id: {}", mb_id);
90        wait_for_enter();
91
92        match client.playlist().get_playlist_file_list(mb_id).await {
93            Ok(pl_files) => {
94                println!("✓ Successfully retrieved playlist file list!");
95                println!(
96                    "  Has more: {}",
97                    if pl_files.has_more == 1 { "Yes" } else { "No" }
98                );
99                println!("  Found {} file(s) in playlist:", pl_files.list.len());
100                for (idx, file) in pl_files.list.iter().enumerate() {
101                    println!(
102                        "    {}. {}",
103                        idx + 1,
104                        file.server_filename.as_deref().unwrap_or("(no name)")
105                    );
106                    println!("       fs_id: {}", file.fs_id);
107                    println!("       path: {}", file.path);
108                    if let Some(size) = &file.size {
109                        println!("       size: {}", size);
110                    }
111                    if let Some(category) = &file.category {
112                        println!("       category: {}", category);
113                    }
114                    if let Some(isdir) = &file.isdir {
115                        println!("       isdir: {}", isdir);
116                    }
117                }
118                Some(pl_files)
119            }
120            Err(e) => {
121                println!("! Failed to get playlist file list: {}", e);
122                None
123            }
124        }
125    } else {
126        println!("  Skipping playlist file list as no valid mb_id was provided");
127        None
128    };
129
130    // === Part 3-4: Get Media and Check M3U8 Generation ===
131    println!("\n=== Part 3-4: Get Media and Check M3U8 Generation ===");
132    println!("Enter the path of the media file to get playback info:");
133    let mut input = String::new();
134    std::io::stdin().read_line(&mut input)?;
135    let media_path = input.trim();
136
137    println!("\nEnter media type (e.g., M3U8_MP3_128, M3U8_AUTO_720, M3U8_AUTO_1080) or press Enter for default:");
138    let mut media_type_input = String::new();
139    std::io::stdin().read_line(&mut media_type_input)?;
140    let media_type = if media_type_input.trim().is_empty() {
141        "M3U8_AUTO_1080".to_string()
142    } else {
143        media_type_input.trim().to_string()
144    };
145
146    let (_selected_fs_id, selected_path) = if media_path.is_empty() && playlist_files.is_some() {
147        // If user just pressed enter and we have files, use the first one
148        println!("  No input provided, using the first file in playlist...");
149        let file = playlist_files.as_ref().and_then(|pf| pf.list.first());
150        (
151            file.and_then(|f| f.fs_id.parse::<u64>().ok()),
152            file.map(|f| f.path.as_str()),
153        )
154    } else {
155        (None, Some(media_path))
156    };
157
158    let target_path = selected_path.unwrap_or_default().to_string();
159    if !target_path.is_empty() {
160        println!("\nStarting m3u8 check process with type: {}", media_type);
161        println!("Path: {}", target_path);
162        println!("Press Enter to check, any other key + Enter to skip");
163
164        let mut attempts = 0;
165        let max_attempts = 100;
166        let mut last_content_len = 0;
167
168        loop {
169            // Wait for user to press enter
170            let mut user_input = String::new();
171            std::io::stdin().read_line(&mut user_input)?;
172            if !user_input.trim().is_empty() && user_input.trim() != "y" && user_input.trim() != "Y"
173            {
174                println!("  Skipping further checks");
175                break;
176            }
177
178            attempts += 1;
179            println!("\n=== Check attempt {}/{} ===", attempts, max_attempts);
180
181            // Try to get m3u8 content directly
182            match client
183                .playlist()
184                .get_media_m3u8_content(&target_path, &media_type)
185                .await
186            {
187                Ok(content) => {
188                    let len = content.len();
189                    let has_end_list = content.contains("#EXT-X-ENDLIST");
190
191                    println!("✓ Got m3u8 content!");
192                    println!("  Length: {} bytes", len);
193                    println!(
194                        "  Has #EXT-X-ENDLIST: {}",
195                        if has_end_list { "Yes" } else { "No" }
196                    );
197
198                    if len > last_content_len {
199                        println!("  Content is growing (was {} bytes)", last_content_len);
200                        last_content_len = len;
201                    } else if len > 0 && len == last_content_len {
202                        println!("  Content size unchanged");
203                    }
204
205                    // Show preview
206                    let preview_lines = content.lines().take(20);
207                    println!("\n  Preview:");
208                    for line in preview_lines {
209                        println!("    {}", line);
210                    }
211                    if content.lines().count() > 20 {
212                        println!("    ... ({} more lines)", content.lines().count() - 20);
213                    }
214
215                    if has_end_list {
216                        println!("\n✅ Media is fully transcoded! Done.");
217                        break;
218                    } else {
219                        println!("\n⏳ Media still transcoding... Press Enter to check again");
220                    }
221                }
222                Err(e) => {
223                    println!("❌ Error getting m3u8: {}", e);
224                    println!("  Stopping check process");
225                    break;
226                }
227            }
228
229            if attempts >= max_attempts {
230                println!("\n⚠️ Max attempts reached. Giving up.");
231                break;
232            }
233        }
234    } else {
235        println!("  Skipping as no valid path was provided");
236    }
237
238    // === Part 5: Using Quality Enums ===
239    println!("\n=== Part 5: Using Quality Enums ===");
240    println!("Test the new VideoQuality and AudioQuality enums? (Y/n):");
241    let mut enum_test_input = String::new();
242    std::io::stdin().read_line(&mut enum_test_input)?;
243
244    if enum_test_input.trim().to_lowercase() != "n" {
245        println!("\nAvailable video qualities for different VIP levels:");
246        println!("  VIP 0-1: {:?}", VideoQuality::available_for_vip_level(0));
247        println!("  VIP 2+: {:?}", VideoQuality::available_for_vip_level(2));
248
249        println!("\nHighest quality for each level:");
250        println!(
251            "  VIP 0: {:?} ({})",
252            VideoQuality::highest_for_vip_level(0),
253            VideoQuality::highest_for_vip_level(0).to_media_type()
254        );
255        println!(
256            "  VIP 2: {:?} ({})",
257            VideoQuality::highest_for_vip_level(2),
258            VideoQuality::highest_for_vip_level(2).to_media_type()
259        );
260
261        // Ask user to test enum methods
262        println!("\nTest enum-based m3u8 methods? (Y/n):");
263        let mut enum_m3u8_input = String::new();
264        std::io::stdin().read_line(&mut enum_m3u8_input)?;
265
266        if enum_m3u8_input.trim().to_lowercase() != "n" {
267            println!("\nEnter media file path:");
268            let mut enum_path_input = String::new();
269            std::io::stdin().read_line(&mut enum_path_input)?;
270            let enum_path = enum_path_input.trim();
271
272            if !enum_path.is_empty() {
273                println!("\nSelect video quality (1=480P, 2=720P, 3=1080P, or press Enter for highest VIP 2):");
274                let mut quality_input = String::new();
275                std::io::stdin().read_line(&mut quality_input)?;
276
277                let quality = match quality_input.trim() {
278                    "1" => VideoQuality::Quality480P,
279                    "2" => VideoQuality::Quality720P,
280                    "3" => VideoQuality::Quality1080P,
281                    _ => VideoQuality::highest_for_vip_level(2), // Default to highest for VIP 2
282                };
283
284                println!(
285                    "\nUsing quality: {:?} ({})",
286                    quality,
287                    quality.to_media_type()
288                );
289                println!("Getting m3u8...");
290                wait_for_enter();
291
292                match client.playlist().get_video_m3u8(enum_path, quality).await {
293                    Ok(content) => {
294                        println!("✓ Successfully got m3u8 content!");
295                        println!("  Length: {} bytes", content.len());
296                        println!(
297                            "  Has #EXT-X-ENDLIST: {}",
298                            content.contains("#EXT-X-ENDLIST")
299                        );
300                    }
301                    Err(e) => {
302                        println!("! Failed to get m3u8: {}", e);
303                    }
304                }
305            }
306        }
307    }
308
309    println!("\n=== All playlist tests completed! ===");
310
311    Ok(())
312}
Source

pub fn config(&self) -> &ClientConfig

Source

pub async fn get_valid_token(&self) -> NetDiskResult<AccessToken>

Examples found in repository?
examples/token_test.rs (line 36)
13async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
14    env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("debug")).init();
15
16    println!("=== Baidu NetDisk Token Test ===\n");
17
18    let client = BaiduNetDiskClient::builder()
19        .auto_refresh(true)
20        .refresh_ahead_seconds(300)
21        .build()?;
22
23    println!("--- Part 1: Create AccessToken using builder ---");
24    let token = AccessToken::new(
25        "your_access_token".to_string(),
26        "your_refresh_token".to_string(),
27        2592000,
28        "basic netdisk".to_string(),
29    );
30    println!("✓ Created AccessToken");
31    println!("  Valid for: {} seconds", token.remaining_seconds());
32
33    println!("\n--- Part 2: Load Token from Environment ---");
34    client.load_token_from_env()?;
35
36    match client.get_valid_token().await {
37        Ok(token) => {
38            println!("✓ Token loaded from environment");
39            println!("  Scope: {}", token.scope);
40            println!("  Valid for: {} seconds", token.remaining_seconds());
41        }
42        Err(e) => {
43            println!("✗ Failed to load token: {}", e);
44            println!("\nSet these environment variables:");
45            println!("  BD_NETDISK_ACCESS_TOKEN");
46            println!("  BD_NETDISK_REFRESH_TOKEN");
47            println!("  BD_NETDISK_EXPIRES_IN");
48        }
49    }
50
51    println!("\n--- Part 3: Validate Token Status ---");
52    match client.validate_token() {
53        Ok(status) => match status {
54            TokenStatus::Valid => println!("✓ Token is valid"),
55            TokenStatus::ExpiringSoon => println!("⚠ Token is expiring soon (< 5 min)"),
56            TokenStatus::Expired => println!("✗ Token is expired"),
57        },
58        Err(e) => println!("✗ No token set: {}", e),
59    }
60
61    println!("\n--- Part 4: Test Expired Token Auto-Refresh ---");
62    let now = SystemTime::now()
63        .duration_since(UNIX_EPOCH)
64        .unwrap_or_default()
65        .as_secs();
66
67    let expired_token = AccessToken::with_all(
68        "test_access_token".to_string(),
69        "test_refresh_token".to_string(),
70        2592000,
71        "basic netdisk".to_string(),
72        String::new(),
73        String::new(),
74        now - 2592000 - 3600,
75    );
76
77    println!("Created expired token:");
78    println!("  Acquired: {} seconds ago", 2592000 + 3600);
79    match expired_token.validate() {
80        TokenStatus::Expired => println!("  Status: Expired ✓"),
81        _ => println!("  Status: Unexpected"),
82    }
83
84    client.set_access_token(expired_token)?;
85
86    println!("\nAttempting to get valid token (will try auto-refresh)...");
87    match client.get_valid_token().await {
88        Ok(new_token) => {
89            println!("✓ Auto-refresh succeeded!");
90            println!(
91                "  New token valid for: {} seconds",
92                new_token.remaining_seconds()
93            );
94        }
95        Err(e) => {
96            println!("✗ Auto-refresh failed: {}", e);
97            println!("  → Need to re-authenticate via device code flow");
98        }
99    }
100
101    println!("\n=== Test Complete ===");
102    Ok(())
103}
More examples
Hide additional examples
examples/token_check.rs (line 24)
7async fn main() -> Result<(), Box<dyn std::error::Error>> {
8    // Initialize logger
9    env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("debug")).init();
10
11    println!("=== Token Validation and Refresh Test ===");
12    println!();
13
14    // Create client
15    let client = BaiduNetDiskClient::builder().build()?;
16
17    println!("Client created successfully");
18    println!();
19
20    // Test 1: Load token from environment
21    println!("Test 1: Loading token from environment...");
22    client.load_token_from_env()?;
23
24    let token = client.get_valid_token().await?;
25    println!("Token loaded successfully: {}", token.access_token);
26    println!();
27
28    // Test 2: Check token validity
29    println!("Test 2: Checking token validity...");
30    println!("Token acquired at: {}", token.acquired_at);
31    println!("Token expires in: {} seconds", token.expires_in);
32    println!("Token remaining seconds: {}", token.remaining_seconds());
33    println!("Token is expired: {}", token.is_expired());
34
35    if !token.is_expired() {
36        println!("✓ Token is valid");
37    } else {
38        println!("✗ Token is expired");
39    }
40    println!();
41
42    // Test 3: Test needs_refresh logic
43    println!("Test 3: Testing needs_refresh logic...");
44    let needs_refresh = client.token_provider().needs_refresh()?;
45    println!("Token needs refresh: {}", needs_refresh);
46
47    if !needs_refresh {
48        println!("✓ Token doesn't need refresh");
49    } else {
50        println!("✗ Token needs refresh");
51    }
52    println!();
53
54    // Test 4: Try to get valid token
55    println!("Test 4: Getting valid token...");
56    match client.get_valid_token().await {
57        Ok(valid_token) => {
58            println!("✓ Got valid token: {}", valid_token.access_token);
59            println!(
60                "Token expires in: {} seconds",
61                valid_token.remaining_seconds()
62            );
63        }
64        Err(e) => {
65            println!("✗ Failed to get valid token: {}", e);
66            println!("Note: This is expected if refresh token is invalid/mock");
67        }
68    }
69    println!();
70
71    // Test 5: Test with an expired token
72    println!("Test 5: Testing with expired token...");
73    let expired_token = AccessToken {
74        access_token: "expired_token".to_string(),
75        expires_in: 1, // 1 second
76        refresh_token: "mock_refresh_token".to_string(),
77        scope: "basic netdisk".to_string(),
78        session_key: "".to_string(),
79        session_secret: "".to_string(),
80        acquired_at: SystemTime::now()
81            .duration_since(UNIX_EPOCH)
82            .unwrap_or_default()
83            .as_secs()
84            - 10, // 10 seconds ago
85    };
86
87    client.set_access_token(expired_token.clone())?;
88    println!(
89        "Expired token remaining seconds: {}",
90        expired_token.remaining_seconds()
91    );
92    println!("Expired token is_expired: {}", expired_token.is_expired());
93
94    if expired_token.is_expired() {
95        println!("✓ Expired token correctly identified");
96    } else {
97        println!("✗ Failed to identify expired token");
98    }
99    println!();
100
101    println!("=== Test completed ===");
102    Ok(())
103}
examples/token_refresh.rs (line 28)
7async fn main() -> Result<(), Box<dyn std::error::Error>> {
8    // Initialize logger
9    env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("debug")).init();
10
11    println!("=== Token Refresh Test ===");
12    println!();
13
14    // Create client with auto-refresh enabled
15    let client = BaiduNetDiskClient::builder()
16        .auto_refresh(true)
17        .refresh_ahead_seconds(60)
18        .build()?;
19
20    println!("Client created successfully");
21    println!();
22
23    // Step 1: Load token from environment
24    println!("Step 1: Loading token from environment...");
25    client.load_token_from_env()?;
26    println!("Token loaded successfully");
27
28    let original_token = client.get_valid_token().await?;
29    println!("Original Token: {:?}", original_token);
30    println!();
31
32    // Step 2: Test manual refresh
33    println!("Step 2: Testing manual token refresh...");
34    match client.token_provider().refresh_token().await {
35        Ok(new_token) => {
36            println!("✓ Token refreshed successfully!");
37            println!("  New Access Token: {}", new_token.access_token);
38            println!("  New Refresh Token: {}", new_token.refresh_token);
39            println!("  Expires in: {} seconds", new_token.expires_in);
40            println!();
41
42            // Verify the tokens are different
43            if new_token.access_token != original_token.access_token {
44                println!("✓ Access token changed after refresh");
45            } else {
46                println!("✗ Access token remains the same");
47            }
48
49            // Verify refresh token may have changed
50            if new_token.refresh_token != original_token.refresh_token {
51                println!("✓ Refresh token changed after refresh");
52            } else {
53                println!("Note: Refresh token remains the same (may be expected)");
54            }
55        }
56        Err(e) => {
57            println!("✗ Failed to refresh token: {}", e);
58            println!("Note: This may be due to invalid credentials or network issues");
59        }
60    }
61
62    println!();
63
64    // Step 3: Test auto-refresh with expired token simulation
65    println!("Step 3: Testing auto-refresh behavior...");
66
67    // Create an expired token to test auto-refresh
68    let expired_token = AccessToken {
69        access_token: "expired_access_token".to_string(),
70        expires_in: 60,                                      // 60 seconds
71        refresh_token: original_token.refresh_token.clone(), // Use real refresh token
72        scope: "basic netdisk".to_string(),
73        session_key: "".to_string(),
74        session_secret: "".to_string(),
75        acquired_at: SystemTime::now()
76            .duration_since(UNIX_EPOCH)
77            .unwrap_or_default()
78            .as_secs()
79            - 3600, // 1 hour ago (expired)
80    };
81
82    client.set_access_token(expired_token)?;
83
84    // Now try to get valid token - should trigger auto-refresh
85    match client.get_valid_token().await {
86        Ok(refreshed_token) => {
87            println!("✓ Auto-refresh triggered successfully!");
88            println!("  New Access Token: {}", refreshed_token.access_token);
89            println!(
90                "  Expires in: {} seconds",
91                refreshed_token.remaining_seconds()
92            );
93        }
94        Err(e) => {
95            println!("✗ Auto-refresh failed: {}", e);
96            println!("Note: This may be due to invalid credentials");
97        }
98    }
99
100    println!();
101    println!("=== Refresh test completed ===");
102    Ok(())
103}
Source

pub fn set_access_token(&self, token: AccessToken) -> NetDiskResult<()>

Examples found in repository?
examples/token_test.rs (line 84)
13async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
14    env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("debug")).init();
15
16    println!("=== Baidu NetDisk Token Test ===\n");
17
18    let client = BaiduNetDiskClient::builder()
19        .auto_refresh(true)
20        .refresh_ahead_seconds(300)
21        .build()?;
22
23    println!("--- Part 1: Create AccessToken using builder ---");
24    let token = AccessToken::new(
25        "your_access_token".to_string(),
26        "your_refresh_token".to_string(),
27        2592000,
28        "basic netdisk".to_string(),
29    );
30    println!("✓ Created AccessToken");
31    println!("  Valid for: {} seconds", token.remaining_seconds());
32
33    println!("\n--- Part 2: Load Token from Environment ---");
34    client.load_token_from_env()?;
35
36    match client.get_valid_token().await {
37        Ok(token) => {
38            println!("✓ Token loaded from environment");
39            println!("  Scope: {}", token.scope);
40            println!("  Valid for: {} seconds", token.remaining_seconds());
41        }
42        Err(e) => {
43            println!("✗ Failed to load token: {}", e);
44            println!("\nSet these environment variables:");
45            println!("  BD_NETDISK_ACCESS_TOKEN");
46            println!("  BD_NETDISK_REFRESH_TOKEN");
47            println!("  BD_NETDISK_EXPIRES_IN");
48        }
49    }
50
51    println!("\n--- Part 3: Validate Token Status ---");
52    match client.validate_token() {
53        Ok(status) => match status {
54            TokenStatus::Valid => println!("✓ Token is valid"),
55            TokenStatus::ExpiringSoon => println!("⚠ Token is expiring soon (< 5 min)"),
56            TokenStatus::Expired => println!("✗ Token is expired"),
57        },
58        Err(e) => println!("✗ No token set: {}", e),
59    }
60
61    println!("\n--- Part 4: Test Expired Token Auto-Refresh ---");
62    let now = SystemTime::now()
63        .duration_since(UNIX_EPOCH)
64        .unwrap_or_default()
65        .as_secs();
66
67    let expired_token = AccessToken::with_all(
68        "test_access_token".to_string(),
69        "test_refresh_token".to_string(),
70        2592000,
71        "basic netdisk".to_string(),
72        String::new(),
73        String::new(),
74        now - 2592000 - 3600,
75    );
76
77    println!("Created expired token:");
78    println!("  Acquired: {} seconds ago", 2592000 + 3600);
79    match expired_token.validate() {
80        TokenStatus::Expired => println!("  Status: Expired ✓"),
81        _ => println!("  Status: Unexpected"),
82    }
83
84    client.set_access_token(expired_token)?;
85
86    println!("\nAttempting to get valid token (will try auto-refresh)...");
87    match client.get_valid_token().await {
88        Ok(new_token) => {
89            println!("✓ Auto-refresh succeeded!");
90            println!(
91                "  New token valid for: {} seconds",
92                new_token.remaining_seconds()
93            );
94        }
95        Err(e) => {
96            println!("✗ Auto-refresh failed: {}", e);
97            println!("  → Need to re-authenticate via device code flow");
98        }
99    }
100
101    println!("\n=== Test Complete ===");
102    Ok(())
103}
More examples
Hide additional examples
examples/token_check.rs (line 87)
7async fn main() -> Result<(), Box<dyn std::error::Error>> {
8    // Initialize logger
9    env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("debug")).init();
10
11    println!("=== Token Validation and Refresh Test ===");
12    println!();
13
14    // Create client
15    let client = BaiduNetDiskClient::builder().build()?;
16
17    println!("Client created successfully");
18    println!();
19
20    // Test 1: Load token from environment
21    println!("Test 1: Loading token from environment...");
22    client.load_token_from_env()?;
23
24    let token = client.get_valid_token().await?;
25    println!("Token loaded successfully: {}", token.access_token);
26    println!();
27
28    // Test 2: Check token validity
29    println!("Test 2: Checking token validity...");
30    println!("Token acquired at: {}", token.acquired_at);
31    println!("Token expires in: {} seconds", token.expires_in);
32    println!("Token remaining seconds: {}", token.remaining_seconds());
33    println!("Token is expired: {}", token.is_expired());
34
35    if !token.is_expired() {
36        println!("✓ Token is valid");
37    } else {
38        println!("✗ Token is expired");
39    }
40    println!();
41
42    // Test 3: Test needs_refresh logic
43    println!("Test 3: Testing needs_refresh logic...");
44    let needs_refresh = client.token_provider().needs_refresh()?;
45    println!("Token needs refresh: {}", needs_refresh);
46
47    if !needs_refresh {
48        println!("✓ Token doesn't need refresh");
49    } else {
50        println!("✗ Token needs refresh");
51    }
52    println!();
53
54    // Test 4: Try to get valid token
55    println!("Test 4: Getting valid token...");
56    match client.get_valid_token().await {
57        Ok(valid_token) => {
58            println!("✓ Got valid token: {}", valid_token.access_token);
59            println!(
60                "Token expires in: {} seconds",
61                valid_token.remaining_seconds()
62            );
63        }
64        Err(e) => {
65            println!("✗ Failed to get valid token: {}", e);
66            println!("Note: This is expected if refresh token is invalid/mock");
67        }
68    }
69    println!();
70
71    // Test 5: Test with an expired token
72    println!("Test 5: Testing with expired token...");
73    let expired_token = AccessToken {
74        access_token: "expired_token".to_string(),
75        expires_in: 1, // 1 second
76        refresh_token: "mock_refresh_token".to_string(),
77        scope: "basic netdisk".to_string(),
78        session_key: "".to_string(),
79        session_secret: "".to_string(),
80        acquired_at: SystemTime::now()
81            .duration_since(UNIX_EPOCH)
82            .unwrap_or_default()
83            .as_secs()
84            - 10, // 10 seconds ago
85    };
86
87    client.set_access_token(expired_token.clone())?;
88    println!(
89        "Expired token remaining seconds: {}",
90        expired_token.remaining_seconds()
91    );
92    println!("Expired token is_expired: {}", expired_token.is_expired());
93
94    if expired_token.is_expired() {
95        println!("✓ Expired token correctly identified");
96    } else {
97        println!("✗ Failed to identify expired token");
98    }
99    println!();
100
101    println!("=== Test completed ===");
102    Ok(())
103}
examples/token_refresh.rs (line 82)
7async fn main() -> Result<(), Box<dyn std::error::Error>> {
8    // Initialize logger
9    env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("debug")).init();
10
11    println!("=== Token Refresh Test ===");
12    println!();
13
14    // Create client with auto-refresh enabled
15    let client = BaiduNetDiskClient::builder()
16        .auto_refresh(true)
17        .refresh_ahead_seconds(60)
18        .build()?;
19
20    println!("Client created successfully");
21    println!();
22
23    // Step 1: Load token from environment
24    println!("Step 1: Loading token from environment...");
25    client.load_token_from_env()?;
26    println!("Token loaded successfully");
27
28    let original_token = client.get_valid_token().await?;
29    println!("Original Token: {:?}", original_token);
30    println!();
31
32    // Step 2: Test manual refresh
33    println!("Step 2: Testing manual token refresh...");
34    match client.token_provider().refresh_token().await {
35        Ok(new_token) => {
36            println!("✓ Token refreshed successfully!");
37            println!("  New Access Token: {}", new_token.access_token);
38            println!("  New Refresh Token: {}", new_token.refresh_token);
39            println!("  Expires in: {} seconds", new_token.expires_in);
40            println!();
41
42            // Verify the tokens are different
43            if new_token.access_token != original_token.access_token {
44                println!("✓ Access token changed after refresh");
45            } else {
46                println!("✗ Access token remains the same");
47            }
48
49            // Verify refresh token may have changed
50            if new_token.refresh_token != original_token.refresh_token {
51                println!("✓ Refresh token changed after refresh");
52            } else {
53                println!("Note: Refresh token remains the same (may be expected)");
54            }
55        }
56        Err(e) => {
57            println!("✗ Failed to refresh token: {}", e);
58            println!("Note: This may be due to invalid credentials or network issues");
59        }
60    }
61
62    println!();
63
64    // Step 3: Test auto-refresh with expired token simulation
65    println!("Step 3: Testing auto-refresh behavior...");
66
67    // Create an expired token to test auto-refresh
68    let expired_token = AccessToken {
69        access_token: "expired_access_token".to_string(),
70        expires_in: 60,                                      // 60 seconds
71        refresh_token: original_token.refresh_token.clone(), // Use real refresh token
72        scope: "basic netdisk".to_string(),
73        session_key: "".to_string(),
74        session_secret: "".to_string(),
75        acquired_at: SystemTime::now()
76            .duration_since(UNIX_EPOCH)
77            .unwrap_or_default()
78            .as_secs()
79            - 3600, // 1 hour ago (expired)
80    };
81
82    client.set_access_token(expired_token)?;
83
84    // Now try to get valid token - should trigger auto-refresh
85    match client.get_valid_token().await {
86        Ok(refreshed_token) => {
87            println!("✓ Auto-refresh triggered successfully!");
88            println!("  New Access Token: {}", refreshed_token.access_token);
89            println!(
90                "  Expires in: {} seconds",
91                refreshed_token.remaining_seconds()
92            );
93        }
94        Err(e) => {
95            println!("✗ Auto-refresh failed: {}", e);
96            println!("Note: This may be due to invalid credentials");
97        }
98    }
99
100    println!();
101    println!("=== Refresh test completed ===");
102    Ok(())
103}
Source

pub fn load_token_from_env(&self) -> NetDiskResult<()>

Examples found in repository?
examples/user_info.rs (line 16)
5async fn main() -> Result<(), Box<dyn std::error::Error>> {
6    env_logger::init();
7
8    println!("=== Baidu NetDisk User Info Test ===\n");
9
10    let client = BaiduNetDiskClient::builder()
11        .app_key("your_app_key")
12        .app_secret("your_app_secret")
13        .build()?;
14    info!("Client created successfully");
15
16    client.load_token_from_env()?;
17    info!("Token loaded successfully");
18
19    println!("Getting user info...");
20    let user_info = client.user().get_user_info(Some("v2")).await?;
21
22    println!("\n=== User Information ===");
23    println!("Baidu Name:    {}", user_info.baidu_name);
24    println!("NetDisk Name:  {}", user_info.netdisk_name);
25    println!("Avatar URL:    {}", user_info.avatar_url);
26    println!(
27        "VIP Type:      {}",
28        match user_info.vip_type {
29            0 => "Regular user",
30            1 => "VIP member",
31            2 => "SVIP super member",
32            _ => "Unknown",
33        }
34    );
35    println!("User ID (uk):  {}", user_info.uk);
36
37    Ok(())
38}
More examples
Hide additional examples
examples/category.rs (line 16)
10async fn main() -> Result<(), Box<dyn std::error::Error>> {
11    env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
12
13    let client = BaiduNetDiskClient::builder().build()?;
14    info!("Client created successfully");
15
16    client.load_token_from_env()?;
17    info!("Token loaded successfully");
18
19    let test_dir = "/apps/product";
20
21    println!("=== Baidu NetDisk Category Test ===\n");
22
23    println!("Testing directory: {}\n", test_dir);
24
25    println!("=== Part 1: Global Category Counts (All files) ===");
26    println!("----------------------------------------");
27    test_global_counts(&client).await?;
28
29    println!("\n\n=== Part 2: Category Counts in {} ===", test_dir);
30    println!("----------------------------------------");
31    test_directory_counts(&client, &test_dir).await?;
32
33    println!("\n\n=== Part 3: List Files in Each Category ===");
34    println!("----------------------------------------");
35    test_list_category_files(&client, &test_dir).await?;
36
37    println!("\n\n=== Category Test Completed ===");
38
39    Ok(())
40}
examples/upload_file.rs (line 11)
5async fn main() -> Result<(), Box<dyn std::error::Error>> {
6    env_logger::init();
7
8    let client = BaiduNetDiskClient::builder().build()?;
9    info!("Client created successfully");
10
11    client.load_token_from_env()?;
12    info!("Token loaded successfully");
13
14    let args: Vec<String> = std::env::args().collect();
15
16    if args.len() < 3 {
17        println!("Usage: {} <local_file> <remote_path>", args[0]);
18        println!("Example: {} test.txt /apps/test/test.txt", args[0]);
19        return Ok(());
20    }
21
22    let local_file = &args[1];
23    let remote_path = &args[2];
24
25    println!("=== Baidu NetDisk File Upload (Simple) ===");
26    println!("Local file: {}", local_file);
27    println!("Remote path: {}", remote_path);
28    println!();
29
30    let start_time = std::time::Instant::now();
31
32    let response = client.upload().upload_file(local_file, remote_path).await?;
33
34    println!("File uploaded successfully!");
35    println!("  FS ID: {}", response.fs_id);
36    println!("  Server filename: {:?}", response.server_filename);
37    println!("  Path: {}", response.path);
38    println!("  Size: {} bytes", response.size);
39    println!("  Category: {}", response.category);
40    println!("  MD5: {}", response.md5.unwrap_or_default());
41    println!("  Upload time: {:?}", start_time.elapsed());
42
43    Ok(())
44}
examples/upload_bytes.rs (line 11)
5async fn main() -> Result<(), Box<dyn std::error::Error>> {
6    env_logger::init();
7
8    let client = BaiduNetDiskClient::builder().build()?;
9    info!("Client created successfully");
10
11    client.load_token_from_env()?;
12    info!("Token loaded successfully");
13
14    let args: Vec<String> = std::env::args().collect();
15
16    let remote_path = if args.len() >= 2 {
17        &args[1]
18    } else {
19        "/upload/hello_bytes.txt"
20    };
21
22    println!("=== Baidu NetDisk Bytes Upload (Simple) ===");
23    println!("Remote path: {}", remote_path);
24    println!();
25
26    let test_data = b"Hello from upload_bytes! This is a simple byte array upload test.";
27    println!("Uploading {} bytes of data...", test_data.len());
28
29    let start_time = std::time::Instant::now();
30
31    let response = client.upload().upload_bytes(test_data, remote_path).await?;
32
33    println!("Bytes uploaded successfully!");
34    println!("  FS ID: {}", response.fs_id);
35    println!("  Server filename: {:?}", response.server_filename);
36    println!("  Path: {}", response.path);
37    println!("  Size: {} bytes", response.size);
38    println!("  Category: {}", response.category);
39    println!("  MD5: {}", response.md5.unwrap_or_default());
40    println!("  Upload time: {:?}", start_time.elapsed());
41
42    Ok(())
43}
examples/upload_reader.rs (line 12)
6async fn main() -> Result<(), Box<dyn std::error::Error>> {
7    env_logger::init();
8
9    let client = BaiduNetDiskClient::builder().build()?;
10    info!("Client created successfully");
11
12    client.load_token_from_env()?;
13    info!("Token loaded successfully");
14
15    let args: Vec<String> = std::env::args().collect();
16
17    let local_file = if args.len() >= 2 {
18        &args[1]
19    } else {
20        println!("Usage: {} <local_file> [remote_path]", args[0]);
21        println!("Example: {} test.txt /upload/test.txt", args[0]);
22        return Ok(());
23    };
24
25    let remote_path = if args.len() >= 3 {
26        &args[2]
27    } else {
28        "/upload/test_reader.txt"
29    };
30
31    println!("=== Baidu NetDisk Reader Upload ===");
32    println!("Local file: {}", local_file);
33    println!("Remote path: {}", remote_path);
34    println!();
35
36    let file = std::fs::File::open(local_file)?;
37    let metadata = file.metadata()?;
38    let file_size = metadata.len();
39
40    println!("File size: {} bytes", file_size);
41
42    let mut reader = BufReader::new(file);
43
44    let start_time = std::time::Instant::now();
45
46    let response = client
47        .upload()
48        .upload_reader(&mut reader, file_size, remote_path)
49        .await?;
50
51    println!("File uploaded successfully!");
52    println!("  FS ID: {}", response.fs_id);
53    println!("  Server filename: {:?}", response.server_filename);
54    println!("  Path: {}", response.path);
55    println!("  Size: {} bytes", response.size);
56    println!("  Category: {}", response.category);
57    println!("  MD5: {}", response.md5.unwrap_or_default());
58    println!("  Upload time: {:?}", start_time.elapsed());
59
60    Ok(())
61}
examples/upload_precreate.rs (line 49)
43async fn main() -> Result<(), Box<dyn std::error::Error>> {
44    env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
45
46    let client = BaiduNetDiskClient::builder().build()?;
47    info!("Client created successfully");
48
49    client.load_token_from_env()?;
50    info!("Token loaded successfully");
51
52    let args: Vec<String> = std::env::args().collect();
53
54    if args.len() < 3 {
55        println!("Usage: {} <local_file> <remote_path>", args[0]);
56        println!("Example: {} test.txt /apps/test/test.txt", args[0]);
57        return Ok(());
58    }
59
60    let local_file = &args[1];
61    let remote_path = &args[2];
62
63    println!("=== Baidu NetDisk Preupload Test ===");
64    println!("Local file: {}", local_file);
65    println!("Remote path: {}", remote_path);
66    println!();
67
68    let (file_size, block_list) = get_file_md5blocks(local_file, 4 * 1024 * 1024)?;
69    let file_md5 = calculate_md5(local_file)?;
70
71    println!("File size: {} bytes", file_size);
72    println!("File MD5: {}", file_md5);
73    println!("Block count: {}", block_list.len());
74    println!("Block list: {:?}", block_list);
75    println!();
76
77    let options = PrecreateOptions::new(remote_path, file_size, block_list)
78        .content_md5(&file_md5)
79        .rtype(1);
80
81    println!("Sending precreate request...");
82    match client.upload().precreate(options).await {
83        Ok(response) => {
84            println!("Precreate success!");
85            println!("  Upload ID: {}", response.uploadid);
86            println!("  Path: {:?}", response.path);
87            println!("  Return type: {}", response.return_type);
88            println!("  Block list to upload: {:?}", response.block_list);
89        }
90        Err(e) => {
91            println!("Precreate failed: {}", e);
92        }
93    }
94
95    Ok(())
96}
Source

pub fn validate_token(&self) -> NetDiskResult<TokenStatus>

Examples found in repository?
examples/token_test.rs (line 52)
13async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
14    env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("debug")).init();
15
16    println!("=== Baidu NetDisk Token Test ===\n");
17
18    let client = BaiduNetDiskClient::builder()
19        .auto_refresh(true)
20        .refresh_ahead_seconds(300)
21        .build()?;
22
23    println!("--- Part 1: Create AccessToken using builder ---");
24    let token = AccessToken::new(
25        "your_access_token".to_string(),
26        "your_refresh_token".to_string(),
27        2592000,
28        "basic netdisk".to_string(),
29    );
30    println!("✓ Created AccessToken");
31    println!("  Valid for: {} seconds", token.remaining_seconds());
32
33    println!("\n--- Part 2: Load Token from Environment ---");
34    client.load_token_from_env()?;
35
36    match client.get_valid_token().await {
37        Ok(token) => {
38            println!("✓ Token loaded from environment");
39            println!("  Scope: {}", token.scope);
40            println!("  Valid for: {} seconds", token.remaining_seconds());
41        }
42        Err(e) => {
43            println!("✗ Failed to load token: {}", e);
44            println!("\nSet these environment variables:");
45            println!("  BD_NETDISK_ACCESS_TOKEN");
46            println!("  BD_NETDISK_REFRESH_TOKEN");
47            println!("  BD_NETDISK_EXPIRES_IN");
48        }
49    }
50
51    println!("\n--- Part 3: Validate Token Status ---");
52    match client.validate_token() {
53        Ok(status) => match status {
54            TokenStatus::Valid => println!("✓ Token is valid"),
55            TokenStatus::ExpiringSoon => println!("⚠ Token is expiring soon (< 5 min)"),
56            TokenStatus::Expired => println!("✗ Token is expired"),
57        },
58        Err(e) => println!("✗ No token set: {}", e),
59    }
60
61    println!("\n--- Part 4: Test Expired Token Auto-Refresh ---");
62    let now = SystemTime::now()
63        .duration_since(UNIX_EPOCH)
64        .unwrap_or_default()
65        .as_secs();
66
67    let expired_token = AccessToken::with_all(
68        "test_access_token".to_string(),
69        "test_refresh_token".to_string(),
70        2592000,
71        "basic netdisk".to_string(),
72        String::new(),
73        String::new(),
74        now - 2592000 - 3600,
75    );
76
77    println!("Created expired token:");
78    println!("  Acquired: {} seconds ago", 2592000 + 3600);
79    match expired_token.validate() {
80        TokenStatus::Expired => println!("  Status: Expired ✓"),
81        _ => println!("  Status: Unexpected"),
82    }
83
84    client.set_access_token(expired_token)?;
85
86    println!("\nAttempting to get valid token (will try auto-refresh)...");
87    match client.get_valid_token().await {
88        Ok(new_token) => {
89            println!("✓ Auto-refresh succeeded!");
90            println!(
91                "  New token valid for: {} seconds",
92                new_token.remaining_seconds()
93            );
94        }
95        Err(e) => {
96            println!("✗ Auto-refresh failed: {}", e);
97            println!("  → Need to re-authenticate via device code flow");
98        }
99    }
100
101    println!("\n=== Test Complete ===");
102    Ok(())
103}
Source

pub fn with_token(&self, token: AccessToken) -> TokenScopedClient

Trait Implementations§

Source§

impl Clone for BaiduNetDiskClient

Source§

fn clone(&self) -> BaiduNetDiskClient

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for BaiduNetDiskClient

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more