releases/VideoDownloader.Cli/Program.cs

93 lines
3.9 KiB
C#

using VideoDownloader.Core.Config;
using VideoDownloader.Core.Dash;
using VideoDownloader.Core.Hls;
using VideoDownloader.Core.Models;
// [임시] 실제 공개 DASH 매니페스트 파싱 검증: 트랙/세그먼트 구조 출력.
if (args.Length > 0 && args[0] == "--dashparse")
{
var mpdUrl = args.Length > 1 ? args[1] : "https://dash.akamaized.net/akamai/bbb_30fps/bbb_30fps.mpd";
using var h = new HttpClient();
h.DefaultRequestHeaders.UserAgent.ParseAdd("Mozilla/5.0");
var xml = await h.GetStringAsync(mpdUrl);
Console.WriteLine($"MPD {xml.Length} bytes");
var m = DashParser.Parse(xml, new Uri(mpdUrl));
if (m == null) { Console.WriteLine("PARSE NULL"); return 1; }
if (m.Video != null) Console.WriteLine($"VIDEO: init={m.Video.InitUrl} segs={m.Video.Segments.Count} first={m.Video.Segments.FirstOrDefault()?.Url}");
if (m.Audio != null) Console.WriteLine($"AUDIO: init={m.Audio.InitUrl} segs={m.Audio.Segments.Count} first={m.Audio.Segments.FirstOrDefault()?.Url}");
else Console.WriteLine("AUDIO: (없음)");
return 0;
}
// [임시] 실제 공개 DASH 종단간 다운로드 검증.
if (args.Length > 0 && (args[0] == "--dash" || args[0] == "--dashlow"))
{
var mpdUrl = args.Length > 1 ? args[1] : "https://dash.akamaized.net/akamai/bbb_30fps/bbb_30fps.mpd";
var outBase = args.Length > 2 ? args[2] : Path.Combine(Directory.GetCurrentDirectory(), "out", "dash");
Directory.CreateDirectory(Path.GetDirectoryName(outBase)!);
var dashConfig = new AppConfig { Concurrency = 8 };
using var h = new HttpClient();
h.DefaultRequestHeaders.UserAgent.ParseAdd(dashConfig.UserAgent);
h.Timeout = TimeSpan.FromMinutes(5);
var dl = new DashDownloader(h, dashConfig);
var prog = new Progress<DownloadProgress>(p =>
{
if (p.Stage == "downloading") Console.Write($"\rDASH: {p.Completed}/{p.Total} ({p.Percent,5:F1}%) ");
else Console.WriteLine($"\n단계: {p.Stage}");
});
try
{
var final = await dl.DownloadAsync(new Uri(mpdUrl), outBase, prog);
var fi = new FileInfo(final);
Console.WriteLine($"\n완료: {final} ({fi.Length / 1048576.0:F2} MB)");
return 0;
}
catch (Exception e) { Console.WriteLine($"\n오류: {e.GetType().Name}: {e.Message}"); return 1; }
}
// 엔진 하네스: 공개 샘플 HLS 를 받아 파싱→병렬다운로드→병합→ffmpeg 리먹스까지 검증.
// 사용: dotnet run --project VideoDownloader.Cli -- <m3u8 URL> [출력경로(확장자빼고)]
// 기본 URL = Mux 공개 테스트스트림(Tears of Steel 일부)
if (args.Length > 0 && args[0] is "--help" or "-h")
{
Console.WriteLine("Usage: dotnet run --project VideoDownloader.Cli -- <m3u8-url> [outputBase]");
return 0;
}
var url = args.Length > 0 ? args[0] : "https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8";
var outputBase = args.Length > 1
? args[1]
: Path.Combine(Directory.GetCurrentDirectory(), "out", "sample");
Console.WriteLine($"대상: {url}");
Console.WriteLine($"출력: {outputBase}.mp4");
var config = new AppConfig { Concurrency = 8 };
using var http = new HttpClient();
http.DefaultRequestHeaders.UserAgent.ParseAdd(config.UserAgent);
http.Timeout = TimeSpan.FromMinutes(3);
var downloader = new HlsDownloader(http, config);
var progress = new Progress<DownloadProgress>(p =>
{
if (p.Stage == "downloading")
Console.Write($"\r다운로드: {p.Completed}/{p.Total} ({p.Percent,5:F1}%) ");
else
Console.WriteLine($"\n단계: {p.Stage} ...");
});
var sw = System.Diagnostics.Stopwatch.StartNew();
try
{
var final = await downloader.DownloadAsync(new Uri(url), outputBase, progress);
sw.Stop();
var fi = new FileInfo(final);
Console.WriteLine($"\n완료: {final}");
Console.WriteLine($"크기: {fi.Length / 1024.0 / 1024.0:F2} MB / 소요: {sw.Elapsed.TotalSeconds:F1}s");
return 0;
}
catch (Exception e)
{
Console.WriteLine($"\n오류: {e.GetType().Name}: {e.Message}");
return 1;
}