pub struct BaiduNetDiskClient { /* private fields */ }Implementations§
Source§impl BaiduNetDiskClient
impl BaiduNetDiskClient
Sourcepub fn builder() -> ClientBuilder
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
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}Additional examples can be found in:
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}Sourcepub fn token_provider(&self) -> &TokenProvider
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
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}Sourcepub fn user(&self) -> &UserClient
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}Sourcepub fn quota(&self) -> &QuotaClient
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}Sourcepub fn file(&self) -> &FileClient
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
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, ¶llel_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(¶llel_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}Additional examples can be found in:
Sourcepub fn download(&self) -> &DownloadClient
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, ¶llel_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
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(¶llel_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}Sourcepub fn upload(&self) -> &UploadClient
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
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}Sourcepub fn playlist(&self) -> &PlaylistClient
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}pub fn config(&self) -> &ClientConfig
Sourcepub async fn get_valid_token(&self) -> NetDiskResult<AccessToken>
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
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}Sourcepub fn set_access_token(&self, token: AccessToken) -> NetDiskResult<()>
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
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}Sourcepub fn load_token_from_env(&self) -> NetDiskResult<()>
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
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}Additional examples can be found in:
Sourcepub fn validate_token(&self) -> NetDiskResult<TokenStatus>
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}pub fn with_token(&self, token: AccessToken) -> TokenScopedClient
Trait Implementations§
Source§impl Clone for BaiduNetDiskClient
impl Clone for BaiduNetDiskClient
Source§fn clone(&self) -> BaiduNetDiskClient
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)
fn clone_from(&mut self, source: &Self)
Performs copy-assignment from
source. Read moreAuto Trait Implementations§
impl Freeze for BaiduNetDiskClient
impl !RefUnwindSafe for BaiduNetDiskClient
impl Send for BaiduNetDiskClient
impl Sync for BaiduNetDiskClient
impl Unpin for BaiduNetDiskClient
impl UnsafeUnpin for BaiduNetDiskClient
impl !UnwindSafe for BaiduNetDiskClient
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more