1- using M3Undle . Core ;
21using M3Undle . Core . Net ;
32using Spectre . Console ;
43
@@ -8,161 +7,65 @@ internal sealed class InteractiveSourceFetcher
87{
98 private readonly HttpClient _httpClient ;
109 private readonly TextWriter _diagnostics ;
10+ private readonly SourceFetcher _sourceFetcher ;
1111
1212 public InteractiveSourceFetcher ( HttpClient httpClient , TextWriter diagnostics )
1313 {
1414 _httpClient = httpClient ;
1515 _diagnostics = diagnostics ;
16+ _sourceFetcher = new SourceFetcher ( httpClient , diagnostics ) ;
1617 }
1718
1819 public async Task < string > GetStringWithProgressAsync ( string source , IAnsiConsole console , CancellationToken cancellationToken )
1920 {
20- if ( string . IsNullOrWhiteSpace ( source ) )
21- {
22- throw new CliException ( "Playlist URL was not provided." , ExitCodes . ConfigError ) ;
23- }
24-
2521 if ( Uri . TryCreate ( source , UriKind . Absolute , out var uri ) &&
2622 ( uri . Scheme == Uri . UriSchemeHttp || uri . Scheme == Uri . UriSchemeHttps ) )
2723 {
28- try
29- {
30- if ( _diagnostics != TextWriter . Null )
31- {
32- await _diagnostics . WriteLineAsync ( $ "Downloading { UrlRedactor . RedactUrl ( uri ) } ...") ;
33- }
34-
35- using var response = await _httpClient . GetAsync ( uri , HttpCompletionOption . ResponseHeadersRead , cancellationToken ) ;
36-
37- if ( _diagnostics != TextWriter . Null )
24+ using var response = await HttpFetcher . SendAndValidateAsync (
25+ _httpClient , uri , _diagnostics , cancellationToken ,
26+ HttpCompletionOption . ResponseHeadersRead ) ;
27+
28+ var total = response . Content . Headers . ContentLength ?? - 1L ;
29+ await using var stream = await response . Content . ReadAsStreamAsync ( cancellationToken ) ;
30+ using var ms = new MemoryStream ( ) ;
31+ var buffer = new byte [ 8192 ] ;
32+ long read = 0 ;
33+
34+ var result = string . Empty ;
35+ await console . Progress ( )
36+ . AutoClear ( true )
37+ . Columns ( CreateColumns ( total ) )
38+ . StartAsync ( async ctx =>
3839 {
39- await _diagnostics . WriteLineAsync ( $ "Response status: { ( int ) response . StatusCode } { response . ReasonPhrase } ") ;
40- await _diagnostics . WriteLineAsync ( $ "Content-Type: { response . Content . Headers . ContentType } ") ;
41- await _diagnostics . WriteLineAsync ( $ "Content-Length: { response . Content . Headers . ContentLength ? . ToString ( ) ?? "unknown" } ") ;
42- }
43-
44- if ( response . StatusCode == System . Net . HttpStatusCode . Unauthorized ||
45- response . StatusCode == System . Net . HttpStatusCode . Forbidden )
46- {
47- throw new CliException ( $ "Authentication failed when requesting { UrlRedactor . RedactUrl ( uri ) } ", ExitCodes . AuthError ) ;
48- }
49-
50- if ( ! response . IsSuccessStatusCode )
51- {
52- var errorBody = string . Empty ;
53- try
54- {
55- errorBody = await response . Content . ReadAsStringAsync ( cancellationToken ) ;
56-
57- if ( _diagnostics != TextWriter . Null && ! string . IsNullOrWhiteSpace ( errorBody ) )
58- {
59- await _diagnostics . WriteLineAsync ( "=== Server Error Response Body ===" ) ;
60- await _diagnostics . WriteLineAsync ( errorBody ) ;
61- await _diagnostics . WriteLineAsync ( "=== End Server Error Response ===" ) ;
62- }
63-
64- if ( ! string . IsNullOrWhiteSpace ( errorBody ) && errorBody . Length > 500 )
65- {
66- errorBody = errorBody [ ..500 ] + "..." ;
67- }
68- }
69- catch ( Exception ex )
40+ var task = ctx . AddTask ( "Downloading" , maxValue : total > 0 ? total : double . MaxValue ) ;
41+ if ( total <= 0 )
7042 {
71- if ( _diagnostics != TextWriter . Null )
72- {
73- await _diagnostics . WriteLineAsync ( $ "Failed to read error response body: { ex . Message } ") ;
74- }
43+ task . IsIndeterminate = true ;
44+ task . Description = "Downloading (0 B)" ;
7545 }
7646
77- var errorMessage = $ "Request to { UrlRedactor . RedactUrl ( uri ) } failed with status { ( int ) response . StatusCode } ( { response . ReasonPhrase } )." ;
78- if ( ! string . IsNullOrWhiteSpace ( errorBody ) )
47+ int bytesRead ;
48+ while ( ( bytesRead = await stream . ReadAsync ( buffer . AsMemory ( 0 , buffer . Length ) , cancellationToken ) ) > 0 )
7949 {
80- errorMessage += $ " \n Server response: { errorBody } " ;
81- }
50+ ms . Write ( buffer , 0 , bytesRead ) ;
51+ read += bytesRead ;
8252
83- throw new CliException ( errorMessage , ExitCodes . NetworkError ) ;
84- }
53+ task . Increment ( bytesRead ) ;
8554
86- var total = response . Content . Headers . ContentLength ?? - 1L ;
87- await using var stream = await response . Content . ReadAsStreamAsync ( cancellationToken ) ;
88- using var ms = new MemoryStream ( ) ;
89- var buffer = new byte [ 8192 ] ;
90- long read = 0 ;
55+ if ( total > 0 )
56+ task . Value = read ;
57+ else
58+ task . Description = $ "Downloading ( { FormatBytes ( read ) } )" ;
59+ }
9160
92- var result = string . Empty ;
93- await console . Progress ( )
94- . AutoClear ( true )
95- . Columns ( CreateColumns ( total ) )
96- . StartAsync ( async ctx =>
97- {
98- var task = ctx . AddTask ( "Downloading" , maxValue : total > 0 ? total : double . MaxValue ) ;
99- if ( total <= 0 )
100- {
101- task . IsIndeterminate = true ;
102- task . Description = "Downloading (0 B)" ;
103- }
104-
105- int bytesRead ;
106- while ( ( bytesRead = await stream . ReadAsync ( buffer . AsMemory ( 0 , buffer . Length ) , cancellationToken ) ) > 0 )
107- {
108- ms . Write ( buffer , 0 , bytesRead ) ;
109- read += bytesRead ;
110-
111- task . Increment ( bytesRead ) ;
112-
113- if ( total > 0 )
114- {
115- task . Value = read ;
116- }
117- else
118- {
119- task . Description = $ "Downloading ({ FormatBytes ( read ) } )";
120- }
121- }
122-
123- task . StopTask ( ) ;
124- result = System . Text . Encoding . UTF8 . GetString ( ms . ToArray ( ) ) ;
125- } ) ;
126-
127- return result ;
128- }
129- catch ( CliException )
130- {
131- throw ;
132- }
133- catch ( TaskCanceledException ex )
134- {
135- if ( _diagnostics != TextWriter . Null )
136- {
137- await _diagnostics . WriteLineAsync ( $ "Request timed out: { ex } ") ;
138- }
139-
140- throw new CliException ( $ "Request to { UrlRedactor . RedactUrl ( uri ) } timed out: { ex . Message } ", ExitCodes . NetworkError ) ;
141- }
142- catch ( HttpRequestException ex )
143- {
144- if ( _diagnostics != TextWriter . Null )
145- {
146- await _diagnostics . WriteLineAsync ( $ "Request failed: { ex } ") ;
147- }
61+ task . StopTask ( ) ;
62+ result = System . Text . Encoding . UTF8 . GetString ( ms . ToArray ( ) ) ;
63+ } ) ;
14864
149- throw new CliException ( $ "Request to { UrlRedactor . RedactUrl ( uri ) } failed: { ex . Message } ", ExitCodes . NetworkError ) ;
150- }
65+ return result ;
15166 }
15267
153- try
154- {
155- if ( _diagnostics != TextWriter . Null )
156- {
157- await _diagnostics . WriteLineAsync ( $ "Reading file { source } ...") ;
158- }
159-
160- return await File . ReadAllTextAsync ( source , cancellationToken ) ;
161- }
162- catch ( Exception ex ) when ( ex is IOException or UnauthorizedAccessException )
163- {
164- throw new CliException ( $ "Failed to read file { source } : { ex . Message } ", ExitCodes . IoError ) ;
165- }
68+ return await _sourceFetcher . GetStringAsync ( source , cancellationToken ) ;
16669 }
16770
16871 private static ProgressColumn [ ] CreateColumns ( long total )
@@ -190,9 +93,7 @@ private static ProgressColumn[] CreateColumns(long total)
19093 private static string FormatBytes ( long bytes )
19194 {
19295 if ( bytes < 1024 )
193- {
19496 return $ "{ bytes } B";
195- }
19697
19798 string [ ] units = [ "KB" , "MB" , "GB" , "TB" ] ;
19899 double value = bytes ;
0 commit comments