@@ -39,8 +39,8 @@ static IHost BuildHost(string[] args)
3939 builder . Services . AddSingleton < IWatchHistoryStore , SqliteWatchHistoryStore > ( ) ;
4040 builder . Logging . SetMinimumLevel ( LogLevel . Warning ) ;
4141 builder . Logging . AddFilter ( "koware" , LogLevel . Information ) ;
42- builder . Logging . AddFilter ( "Koware" , LogLevel . Information ) ;
4342 builder . Logging . AddFilter ( "Koware.Infrastructure.Scraping.GogoAnimeCatalog" , LogLevel . Error ) ;
43+ builder . Logging . AddFilter ( "Koware.Infrastructure.Scraping.AllAnimeCatalog" , LogLevel . Error ) ;
4444
4545 return builder . Build ( ) ;
4646}
@@ -918,10 +918,7 @@ static async Task<int> HandleDownloadAsync(ScrapeOrchestrator orchestrator, stri
918918 : allAnimeOptions ? . Referer ;
919919 var httpUserAgent = allAnimeOptions ? . UserAgent ;
920920
921- Console . WriteLine ( ) ;
922- Console . ForegroundColor = ConsoleColor . Cyan ;
923- Console . WriteLine ( $ "Downloading { title } - Ep { episode . Number } [{ stream . Quality ?? "auto" } ] ({ index } /{ total } )") ;
924- Console . ResetColor ( ) ;
921+ DownloadConsole . PrintEpisodeHeader ( title , episode , stream . Quality , index , total , outputPath ) ;
925922
926923 var isPlaylist = IsPlaylist ( stream ) ;
927924 var ffmpegPath = ResolveExecutablePath ( "ffmpeg" ) ;
@@ -940,6 +937,9 @@ static async Task<int> HandleDownloadAsync(ScrapeOrchestrator orchestrator, stri
940937 {
941938 await DownloadWithHttpAsync ( httpClient , stream , outputPath , httpReferrer , httpUserAgent , logger , cancellationToken ) ;
942939 }
940+
941+ var episodesLeft = total - index ;
942+ DownloadConsole . PrintEpisodeResult ( outputPath , episodesLeft ) ;
943943 }
944944 catch ( OperationCanceledException )
945945 {
@@ -1267,56 +1267,11 @@ static async Task DownloadWithHttpAsync(HttpClient httpClient, StreamLink stream
12671267 await using var fileStream = new FileStream ( outputPath , FileMode . Create , FileAccess . Write , FileShare . None , 81920 , useAsync : true ) ;
12681268
12691269 var buffer = new byte [ 81920 ] ;
1270- long totalRead = 0 ;
12711270 int read ;
1272- var lastUpdate = DateTimeOffset . UtcNow ;
12731271
12741272 while ( ( read = await responseStream . ReadAsync ( buffer . AsMemory ( 0 , buffer . Length ) , cancellationToken ) ) > 0 )
12751273 {
12761274 await fileStream . WriteAsync ( buffer . AsMemory ( 0 , read ) , cancellationToken ) ;
1277- totalRead += read ;
1278-
1279- var now = DateTimeOffset . UtcNow ;
1280- if ( now - lastUpdate > TimeSpan . FromMilliseconds ( 100 ) )
1281- {
1282- lastUpdate = now ;
1283- RenderDownloadProgress ( totalRead , total ) ;
1284- }
1285- }
1286-
1287- RenderDownloadProgress ( totalRead , total ) ;
1288- Console . WriteLine ( ) ;
1289-
1290- static void RenderDownloadProgress ( long bytesRead , long ? totalBytes )
1291- {
1292- var readMb = bytesRead / ( 1024.0 * 1024.0 ) ;
1293- string text ;
1294-
1295- if ( totalBytes . HasValue && totalBytes . Value > 0 )
1296- {
1297- var totalMb = totalBytes . Value / ( 1024.0 * 1024.0 ) ;
1298- var progress = Math . Clamp ( bytesRead / ( double ) totalBytes . Value , 0 , 1 ) ;
1299- const int width = 30 ;
1300- var filled = ( int ) ( progress * width ) ;
1301- if ( filled > width )
1302- {
1303- filled = width ;
1304- }
1305-
1306- var bar = new string ( '#' , filled ) + new string ( '-' , width - filled ) ;
1307- text = $ "[{ bar } ] { progress * 100 , 5 : 0.0} % { readMb , 6 : 0.0} /{ totalMb , 6 : 0.0} MiB";
1308- }
1309- else
1310- {
1311- text = $ "Downloaded { readMb : 0.0} MiB";
1312- }
1313-
1314- if ( text . Length > 80 )
1315- {
1316- text = text [ ..80 ] ;
1317- }
1318-
1319- Console . Write ( "\r " + text . PadRight ( 80 ) ) ;
13201275 }
13211276}
13221277
@@ -1342,41 +1297,72 @@ static string BuildFfmpegHeaders(string? httpReferrer, string? httpUserAgent)
13421297 return string . Join ( "\r \n " , parts ) + "\r \n " ;
13431298}
13441299
1345- static Task DownloadWithFfmpegAsync ( string ffmpegPath , StreamLink stream , string outputPath , string ? httpReferrer , string ? httpUserAgent , ILogger logger , CancellationToken cancellationToken )
1300+ static async Task DownloadWithFfmpegAsync ( string ffmpegPath , StreamLink stream , string outputPath , string ? httpReferrer , string ? httpUserAgent , ILogger logger , CancellationToken cancellationToken )
13461301{
1347- return Task . Run ( ( ) =>
1302+ cancellationToken . ThrowIfCancellationRequested ( ) ;
1303+
1304+ var start = new ProcessStartInfo
13481305 {
1349- cancellationToken . ThrowIfCancellationRequested ( ) ;
1306+ FileName = ffmpegPath ,
1307+ UseShellExecute = false ,
1308+ RedirectStandardError = true ,
1309+ RedirectStandardOutput = true ,
1310+ CreateNoWindow = true
1311+ } ;
13501312
1351- var start = new ProcessStartInfo
1352- {
1353- FileName = ffmpegPath ,
1354- UseShellExecute = false
1355- } ;
1313+ start . ArgumentList . Add ( "-y" ) ;
1314+ start . ArgumentList . Add ( "-loglevel" ) ;
1315+ start . ArgumentList . Add ( "error" ) ;
1316+
1317+ var headers = BuildFfmpegHeaders ( httpReferrer , httpUserAgent ) ;
1318+ if ( ! string . IsNullOrWhiteSpace ( headers ) )
1319+ {
1320+ start . ArgumentList . Add ( "-headers" ) ;
1321+ start . ArgumentList . Add ( headers ) ;
1322+ }
13561323
1357- start . ArgumentList . Add ( "-y" ) ;
1324+ start . ArgumentList . Add ( "-i" ) ;
1325+ start . ArgumentList . Add ( stream . Url . ToString ( ) ) ;
1326+ start . ArgumentList . Add ( "-c" ) ;
1327+ start . ArgumentList . Add ( "copy" ) ;
1328+ start . ArgumentList . Add ( "-bsf:a" ) ;
1329+ start . ArgumentList . Add ( "aac_adtstoasc" ) ;
1330+ start . ArgumentList . Add ( outputPath ) ;
13581331
1359- var headers = BuildFfmpegHeaders ( httpReferrer , httpUserAgent ) ;
1360- if ( ! string . IsNullOrWhiteSpace ( headers ) )
1332+ using var process = new Process { StartInfo = start } ;
1333+
1334+ try
1335+ {
1336+ if ( ! process . Start ( ) )
13611337 {
1362- start . ArgumentList . Add ( "-headers" ) ;
1363- start . ArgumentList . Add ( headers ) ;
1338+ throw new InvalidOperationException ( "Failed to start ffmpeg process." ) ;
13641339 }
13651340
1366- start . ArgumentList . Add ( "-i" ) ;
1367- start . ArgumentList . Add ( stream . Url . ToString ( ) ) ;
1368- start . ArgumentList . Add ( "-c" ) ;
1369- start . ArgumentList . Add ( "copy" ) ;
1370- start . ArgumentList . Add ( "-bsf:a" ) ;
1371- start . ArgumentList . Add ( "aac_adtstoasc" ) ;
1372- start . ArgumentList . Add ( outputPath ) ;
1373-
1374- var exitCode = StartProcessAndWait ( logger , start , ffmpegPath ) ;
1375- if ( exitCode != 0 )
1341+ _ = process . StandardError . ReadToEndAsync ( ) ;
1342+ _ = process . StandardOutput . ReadToEndAsync ( ) ;
1343+
1344+ await Task . Run ( ( ) => process . WaitForExit ( ) , cancellationToken ) ;
1345+
1346+ if ( process . ExitCode != 0 )
13761347 {
1377- throw new InvalidOperationException ( $ "ffmpeg exited with code { exitCode } .") ;
1348+ throw new InvalidOperationException ( $ "ffmpeg exited with code { process . ExitCode } .") ;
13781349 }
1379- } , cancellationToken ) ;
1350+ }
1351+ catch
1352+ {
1353+ try
1354+ {
1355+ if ( ! process . HasExited )
1356+ {
1357+ process . Kill ( entireProcessTree : true ) ;
1358+ }
1359+ }
1360+ catch
1361+ {
1362+ }
1363+
1364+ throw ;
1365+ }
13801366}
13811367
13821368static string ? ResolveExecutablePath ( string command )
0 commit comments