using System.Windows.Threading; using VideoDownloader.App.ViewModels; using VideoDownloader.Server; using VideoDownloader.Core.Detection; namespace VideoDownloader.App.Services; /// /// DownloadManager(UI 컬렉션) ↔ 서버 큐 API 브릿지. 모든 접근을 UI 디스패처로 마샬링. /// public sealed class DownloadQueueAdapter : IQueueAdapter { private readonly Core.DownloadManager _manager; private readonly Dispatcher _dispatcher; public DownloadQueueAdapter(Core.DownloadManager manager, Dispatcher dispatcher) { _manager = manager; _dispatcher = dispatcher; } public Task> GetItemsAsync() => _dispatcher.InvokeAsync(() => (IReadOnlyList)_manager.Items.Select(Map).ToList()).Task; public Task AddAsync(string url, string? title) { // 서버에서 온 URL → 감지 파이프라인으로(소셜/HLS/DASH 자동 분류) return _dispatcher.InvokeAsync(() => { if (Uri.TryCreate(url, UriKind.Absolute, out var uri) && SocialSiteDetector.TryMatch(uri, out var normalized, out var label)) { _manager.OnDetected(new DetectionContext(normalized, normalized, MediaKind.Social, Tag: label)); return normalized; } var kind = MediaDetector.Classify(url, "", -1, _manager.Config) ?? MediaKind.Direct; _manager.OnDetected(new DetectionContext(url, url, kind, "")); return url; }).Task; } public Task PauseAsync(string id) => _dispatcher.InvokeAsync(() => { var item = Find(id); if (item != null) _manager.Cancel(item); // v1: 제어 매핑 — 진행 항목 취소 }).Task; public Task ResumeAsync(string id) => _dispatcher.InvokeAsync(() => { var item = Find(id); if (item != null) _ = _manager.RetryDownload(item); }).Task; public Task CancelAsync(string id) => _dispatcher.InvokeAsync(() => { var item = Find(id); if (item != null) _manager.Cancel(item); }).Task; public event Action? Changed { add { } remove { } } private DownloadItemViewModel? Find(string id) => _manager.Items.FirstOrDefault(i => i.Id == id); private static QueueItemDto Map(DownloadItemViewModel i) => new(i.Id, i.Title, i.Url ?? "", i.Status ?? "", i.Progress); }