@@ -10,6 +10,7 @@ extern crate chrono;
1010extern crate ctrlc;
1111extern crate base64;
1212extern crate html2text;
13+ extern crate percent_encoding;
1314
1415use std:: time:: Instant ;
1516use clipboard:: { ClipboardProvider , ClipboardContext } ;
@@ -30,6 +31,7 @@ use chrono::DateTime;
3031use regex:: Regex ;
3132use reqwest:: header:: { HeaderValue , HeaderMap , ETAG , IF_NONE_MATCH , ACCEPT_ENCODING } ;
3233use std:: collections:: HashMap ;
34+ use percent_encoding:: percent_decode;
3335
3436use webbrowser;
3537
@@ -260,7 +262,9 @@ fn get_rss_videos(document: roxmltree::Document, channel_url: &String) -> Vec<It
260262 let url = get_decendant_node ! ( entry, "link" ) . attribute ( "href" ) . unwrap_or ( "" ) ;
261263 let video_title = get_decendant_node ! ( entry, "title" ) . text ( ) . unwrap_or ( "" ) ;
262264 let video_published = get_decendant_node ! ( entry, "published" ) . text ( ) . unwrap_or (
263- get_decendant_node ! ( entry, "updated" ) . text ( ) . unwrap_or ( "" )
265+ get_decendant_node ! ( entry, "updated" ) . text ( ) . unwrap_or (
266+ get_decendant_node ! ( entry, "issued" ) . text ( ) . unwrap_or ( "" )
267+ )
264268 ) ;
265269 let thumbnail = get_decendant_node ! ( entry, "thumbnail" ) . attribute ( "url" ) . unwrap_or ( "" ) ;
266270 if thumbnail != "" . to_string ( ) { kind = ItemKind :: Video }
@@ -369,10 +373,43 @@ fn get_headers(channel_etag: Option<&String>) -> HeaderMap {
369373 headers
370374}
371375
376+ #[ derive( Debug ) ]
377+ struct ChannelURLWithBasicAuth {
378+ channel_url : String ,
379+ password : Option < String > ,
380+ user : Option < String > ,
381+ }
382+
383+ fn parse_basic_auth ( channel_url : & String ) -> ChannelURLWithBasicAuth {
384+ match Regex :: new ( r"^(https://)([^:/]*):([^@/]*)@(.*)$" ) {
385+ Ok ( re) =>
386+ match re. captures ( channel_url) {
387+ Some ( caps) => ChannelURLWithBasicAuth {
388+ channel_url : ( format ! ( "{}{}" , caps[ 1 ] . to_string( ) , caps[ 4 ] . to_string( ) ) ) . to_string ( ) ,
389+ password : Some ( percent_decode ( caps[ 3 ] . as_bytes ( ) ) . decode_utf8_lossy ( ) . to_string ( ) ) ,
390+ user : Some ( percent_decode ( caps[ 2 ] . as_bytes ( ) ) . decode_utf8_lossy ( ) . to_string ( ) ) } ,
391+ None => ChannelURLWithBasicAuth {
392+ channel_url : channel_url. to_string ( ) , password : None , user : None } ,
393+ }
394+ Err ( _) => ChannelURLWithBasicAuth { channel_url : channel_url. to_string ( ) , password : None , user : None } ,
395+ }
396+ }
397+
398+ fn build_request ( channel_url : & String , client : & reqwest:: Client , channel_etag : Option < & String > ) -> reqwest:: RequestBuilder {
399+ let channel_url_with_basic_auth = parse_basic_auth ( & channel_url) ;
400+ match channel_url_with_basic_auth. user {
401+ Some ( user) =>
402+ client. get ( channel_url_with_basic_auth. channel_url . as_str ( ) )
403+ . headers ( get_headers ( channel_etag) ) . basic_auth ( user, channel_url_with_basic_auth. password )
404+ ,
405+ None => client. get ( channel_url_with_basic_auth. channel_url . as_str ( ) )
406+ . headers ( get_headers ( channel_etag) ) ,
407+ }
408+ }
409+
372410async fn get_channel_videos ( client : & reqwest:: Client , channel_url : String , channel_etag : Option < & String > , original_videos : & Items ) -> Option < ChanelItems > {
373411 for _i in 0 ..2 {
374- let request = client. get ( channel_url. as_str ( ) )
375- . headers ( get_headers ( channel_etag) ) ;
412+ let request = build_request ( & channel_url, & client, channel_etag) ;
376413 let wrapped_response = request. send ( ) . await ;
377414 match wrapped_response {
378415 Ok ( response) => {
0 commit comments