11use crate :: { log, re} ;
22
3- use crate :: logger:: LogUnwrap ;
43use crate :: re:: CompoundReplacer ;
54use reqwest:: Client ;
65use serde:: { Deserialize , Serialize } ;
@@ -18,21 +17,6 @@ pub struct TorrentFile {
1817 pub index : u32 ,
1918}
2019
21- #[ derive( Serialize , Debug ) ]
22- pub struct RenameRequest {
23- pub hash : String ,
24- pub name : String ,
25- }
26-
27- #[ derive( Serialize ) ]
28- pub struct RenameFileRequest {
29- pub hash : String ,
30- #[ serde( rename = "oldPath" ) ]
31- pub old_path : String ,
32- #[ serde( rename = "newPath" ) ]
33- pub new_path : String ,
34- }
35-
3620pub async fn authenticate (
3721 client : & Client ,
3822 webui_url : & str ,
@@ -41,20 +25,16 @@ pub async fn authenticate(
4125) -> Result < ( ) , String > {
4226 let auth_url = format ! ( "{}/api/v2/auth/login" , webui_url) ;
4327 let auth_params = [ ( "username" , username) , ( "password" , password) ] ;
44- let auth_response = client
28+ client
4529 . post ( & auth_url)
4630 . form ( & auth_params)
4731 . send ( )
4832 . await
49- . log_unwrap ( "Failed to authenticate with qBittorrent WebUI" ) ;
33+ . and_then ( |resp| resp. error_for_status ( ) )
34+ . map_err ( |e| format ! ( "Failed to authenticate: {}" , e) ) ?;
5035
51- if auth_response. status ( ) . is_success ( ) {
52- log ! ( "Authentication successful" ) ;
53- Ok ( ( ) )
54- } else {
55- log ! ( "Authentication failed: {}" , auth_response. status( ) ) ;
56- Err ( format ! ( "Authentication failed: {}" , auth_response. status( ) ) )
57- }
36+ log ! ( "Authentication successful" ) ;
37+ Ok ( ( ) )
5838}
5939
6040pub async fn get_torrent_info (
@@ -68,26 +48,20 @@ pub async fn get_torrent_info(
6848 . get ( & info_url)
6949 . send ( )
7050 . await
71- . log_unwrap ( "Failed to fetch torrent info" ) ;
72-
73- if !info_response. status ( ) . is_success ( ) {
74- return Err ( format ! (
75- "Failed to fetch torrent info: {}" ,
76- info_response. status( )
77- ) ) ;
78- }
51+ . and_then ( |resp| resp. error_for_status ( ) )
52+ . map_err ( |e| format ! ( "Failed to fetch torrent info: {}" , e) ) ?;
7953
8054 let torrent_info: Vec < TorrentInfo > = info_response
8155 . json ( )
8256 . await
83- . log_unwrap ( "Failed to parse torrent info" ) ;
57+ . map_err ( |e| format ! ( "Failed to parse torrent info: {}" , e ) ) ? ;
8458
8559 if torrent_info. is_empty ( ) {
8660 return Err ( format ! ( "No torrent found with hash: {}" , torrent_hash) ) ;
8761 }
8862
8963 log ! ( "Fetched torrent info for hash: {}" , torrent_hash) ;
90- Ok ( torrent_info[ 0 ] . clone ( ) )
64+ Ok ( torrent_info. into_iter ( ) . next ( ) . unwrap ( ) )
9165}
9266
9367pub async fn get_torrent_files (
@@ -101,15 +75,9 @@ pub async fn get_torrent_files(
10175 . get ( & files_url)
10276 . send ( )
10377 . await
78+ . and_then ( |resp| resp. error_for_status ( ) )
10479 . map_err ( |e| format ! ( "Failed to fetch torrent files: {}" , e) ) ?;
10580
106- if !files_response. status ( ) . is_success ( ) {
107- return Err ( format ! (
108- "Failed to fetch torrent files: {}" ,
109- files_response. status( )
110- ) ) ;
111- }
112-
11381 let torrent_files: Vec < TorrentFile > = files_response
11482 . json ( )
11583 . await
@@ -124,33 +92,19 @@ pub async fn rename_torrent(
12492 torrent_hash : & str ,
12593 compound_replacer : & CompoundReplacer ,
12694) -> Result < ( ) , String > {
127- let torrent = get_torrent_info ( client, webui_url, torrent_hash)
128- . await
129- . log_unwrap ( "Failed to get torrent info" ) ;
130-
95+ let torrent = get_torrent_info ( client, webui_url, torrent_hash) . await ?;
13196 let new_name = compound_replacer. replace ( & torrent. name ) ;
13297
13398 if torrent. name != new_name {
134- let rename_url = format ! ( "{}/api/v2/torrents/rename" , webui_url) ;
135- let rename_request = RenameRequest {
136- hash : torrent. hash . clone ( ) ,
137- name : new_name. to_string ( ) ,
138- } ;
139- let rename_response = client
140- . post ( & rename_url)
141- . form ( & rename_request)
99+ client
100+ . post ( & format ! ( "{}/api/v2/torrents/rename" , webui_url) )
101+ . form ( & [ ( "hash" , & torrent. hash ) , ( "name" , & new_name) ] )
142102 . send ( )
143103 . await
144- . log_unwrap ( "Failed to rename torrent" ) ;
104+ . and_then ( |resp| resp. error_for_status ( ) )
105+ . map_err ( |e| format ! ( "Failed to rename torrent: {}" , e) ) ?;
145106
146- if !rename_response. status ( ) . is_success ( ) {
147- return Err ( format ! (
148- "Failed to rename torrent: {}" ,
149- rename_response. status( )
150- ) ) ;
151- }
152-
153- log ! ( "Torrent renamed to: {}" , new_name) ;
107+ log ! ( "Successfully renamed torrent to: {}" , new_name) ;
154108 }
155109
156110 Ok ( ( ) )
@@ -162,51 +116,38 @@ pub async fn rename_files(
162116 torrent_hash : & str ,
163117 compound_replacer : & CompoundReplacer ,
164118) -> Result < ( ) , String > {
165- let torrent_files: Vec < TorrentFile > = get_torrent_files ( client, webui_url, torrent_hash)
166- . await
167- . log_unwrap ( "Failed to get torrent files" ) ;
168-
119+ let torrent_files: Vec < TorrentFile > = get_torrent_files ( client, webui_url, torrent_hash) . await ?;
120+ let rename_url = format ! ( "{webui_url}/api/v2/torrents/renameFile" ) ;
169121 let mut tasks = JoinSet :: new ( ) ;
170122
123+ // 并行处理每个文件重命名
171124 for file in torrent_files {
172- let new_path = apply_rename_rules_to_file ( & file. name , compound_replacer) ;
173- if file. name != new_path {
174- let rename_file_url = format ! ( "{}/api/v2/torrents/renameFile" , webui_url) ;
175- let rename_file_request = RenameFileRequest {
176- hash : torrent_hash. to_string ( ) ,
177- old_path : file. name . clone ( ) ,
178- new_path : new_path. clone ( ) ,
179- } ;
180- let client = client. clone ( ) ;
181-
182- // 使用 tokio::spawn 并发执行每个重命名请求
183- tasks. spawn ( async move {
184- let result = client
185- . post ( & rename_file_url)
186- . form ( & rename_file_request)
187- . send ( )
188- . await ;
189- match result {
190- Ok ( response) if response. status ( ) . is_success ( ) => {
191- log ! ( "File renamed: {} -> {}" , file. name, new_path) ;
192- Ok ( ( ) )
193- }
194- Ok ( response) => {
195- log ! ( "Failed to rename file: {} -> {}" , file. name, new_path) ;
196- Err ( format ! ( "Failed to rename file: {}" , response. status( ) ) )
197- }
198- Err ( e) => {
199- log ! ( "Failed to rename file: {} -> {}" , file. name, new_path) ;
200- Err ( format ! ( "Failed to rename file: {}" , e) )
201- }
202- }
203- } ) ;
125+ let new_name = apply_rename_rules_to_file ( & file. name , compound_replacer) ;
126+ if file. name == new_name {
127+ continue ;
204128 }
129+
130+ let ( client, url, hash) = ( client. clone ( ) , rename_url. clone ( ) , torrent_hash. to_owned ( ) ) ;
131+
132+ tasks. spawn ( async move {
133+ // 发送重命名请求并处理响应
134+ let result = client
135+ . post ( & url)
136+ . form ( & [ ( "hash" , & hash) , ( "oldPath" , & file. name ) , ( "newPath" , & new_name) ] )
137+ . send ( )
138+ . await
139+ . and_then ( |resp| resp. error_for_status ( ) ) ;
140+ // 返回处理结果与元数据
141+ ( file. name , new_name, result)
142+ } ) ;
205143 }
144+
145+ // 统一处理所有任务结果
206146 while let Some ( res) = tasks. join_next ( ) . await {
207147 match res {
208- Ok ( _) => { }
209- Err ( err) => log ! ( "Error during renaming: {}" , err) ,
148+ Ok ( ( old, new, Ok ( _) ) ) => log ! ( "Success: {} -> {}" , old, new) ,
149+ Ok ( ( old, new, Err ( e) ) ) => log ! ( "Failed: {} -> {} | {}" , old, new, e) ,
150+ Err ( e) => log ! ( "Task execution failed: {}" , e) ,
210151 }
211152 }
212153 Ok ( ( ) )
0 commit comments