Imported from xanstar6067/YT_downloader (
AGENTS.md). Install upstream withnpx skills add xanstar6067/YT_downloader. Copyright stays with the author.
CLAUDE.md — карта проекта YT Downloader
Этот файл — быстрый ориентир по кодовой базе для ускорения поиска и анализа. Общее описание
возможностей, требований и инструкций по сборке/публикации — в README.md, там же
таблица сторонних инструментов (Tools/yt-dlp.exe, ffmpeg.exe, ffprobe.exe, node.exe).
Что это
WPF-приложение (.NET 10, Windows) — GUI-обёртка над yt-dlp.exe. Анализирует ссылку (видео или
плейлист), показывает метаданные, скачивает через yt-dlp + ffmpeg/ffprobe, парсит прогресс
из --progress-template в реальном времени. Без DI-контейнера — сервисы создаются и связываются
вручную в App.xaml.cs.
Структура решения
YT_downloader/ ← корень .sln (YT_downloader.slnx)
├── YT_downloader/ ← WPF-приложение (проект YtDlpDownloader.dll)
│ ├── App.xaml.cs ← composition root: создаёт все сервисы и MainViewModel
│ ├── Views/MainWindow.xaml(.cs) ← единственное окно, чистый MVVM-биндинг
│ ├── ViewModels/
│ │ ├── ViewModelBase.cs ← INotifyPropertyChanged + SetProperty helper
│ │ └── MainViewModel.cs ← всё состояние и сценарии интерфейса (самый большой файл)
│ ├── Models/ ← record-модели (см. ниже)
│ ├── Services/ ← вся логика работы с yt-dlp, настройками, ОС-диалогами
│ ├── Commands/ ← RelayCommand, AsyncRelayCommand (ICommand для MVVM)
│ └── Tools/ ← *.exe бинарники (не в Git, см. README «Подготовка Tools»)
└── YT_downloader.Tests/ ← MSTest-юниты для парсеров и построения аргументов
Модели (Models/)
DownloadRequest— входные параметры скачивания (url, папка, режим, разрешение, аудиоформат, playlist-флаг, cookies-браузер,ConcurrentFragments). Передаётся вYtDlpService.DownloadAsync.DownloadProgress— один «тик» прогресса, разобранный из строки yt-dlp (percent, speed, size, eta, playlist index/count, format/media id, кодеки, номер и общее число фрагментов).VideoInfo— результат анализа: заголовок, миниатюра, длительность, список аудиодорожек, признак плейлиста и число элементов.AudioTrackInfo,BrowserCookieSource,ChoiceItem<T>(пара displayName/value для комбобоксов),DownloadMode(Mp4Video/Mp3Audio),AppSettings(персистентные настройки пользователя),ToolAvailability(какие из 4 инструментов найдены на диске).
Сервисы (Services/)
YtDlpService(реализуетIYtDlpService) — ядро приложения:BuildAnalyzeArguments/BuildDownloadArguments— сборкаArgumentListдля yt-dlp (важно: аргументы передаются списком,cmd.exeне используется, инъекция исключена).NormalizeYouTubeUrl— конвертируетyoutube.com/show/VL<id>вplaylist?list=<id>.AnalyzeAsync— буферизованный запуск с--dump-single-json; для плейлиста добавляется--flat-playlist(быстро, без разбора форматов каждого видео).DownloadAsync— стриминговый запуск с построчным парсингом stdout/stderr; при HTTP 403 (истёкшая подписанная ссылка) один раз перезапускает весь процесс целиком (MaximumDownloadAttempts = 2), см.IsForbiddenDownloadError.--concurrent-fragments Nдобавляется только еслиrequest.ConcurrentFragments > 1(иначе аргумент не передаётся вовсе — поведение yt-dlp по умолчанию).EnsureTools— проверка наличия yt-dlp/ffmpeg/ffprobe/JS-рантайма перед операцией._operationGate(SemaphoreSlim) не даёт двум операциям использовать процесс одновременно;_downloadRunning(Interlocked) — отдельная защита от параллельных загрузок с понятной ошибкойYtDlpErrorKind.AlreadyRunning.
YtDlpProgressParser— чистый парсер строк вывода. Два формата: «человеческий» ([download] NN% of ...) и машинный (download:+ProgressTemplateизYtDlpService, 12/14 полей в зависимости от того, есть ли данные о фрагментах).YtDlpMetadataParser— парсит--dump-single-json: определяет плейлист по_typeили наличиюentries, собирает список аудиодорожек (группировка по языку, выбор лучшего битрейта, отдельно — лучший MP4-совместимый вариант для режима видео).DownloadProgressAggregator— сглаживает прогресс: держит процент монотонным (не даёт шкале прыгать назад), использует позицию фрагмента вместо «сырого» процента, где возможно. ДляMp4Videoс раздельными потоками (video+audio) делит шкалу на 2 стадии по 50% (_fallbackFormatOrder) — отсюда в интерфейсе виден переход «видео» → «аудио».JsonSettingsService— читает/пишет%LOCALAPPDATA%\YtDlpDownloader\settings.json(atomic write через.tmp+File.Move). Любое новое полеAppSettingsне ломает старые файлы (JSON-десериализация даёт значения по умолчанию).WpfThemeService,WpfUserInteractionService— тонкие обёртки над WPF/Win32 (смена темы черезApplication.Resources, диалоги папки/сообщений, буфер обмена).YtDlpException+YtDlpErrorKind— типизированные ошибки для UI;CreateProcessExceptionвYtDlpServiceклассифицирует сырой stderr yt-dlp по ключевым фразам (403, CAPTCHA, video unavailable, сетевые ошибки, отсутствие ffmpeg и т.д.).
ViewModels / Views
MainViewModel— единственная VM. Основные сценарии:AnalyzeAsync,DownloadAsync,UpdateYtDlpAsync, всё черезExecuteOperationAsync(общий try/catch → понятные сообщения,IsBusy, отмена черезCancellationTokenSource). Опции комбобоксов (ResolutionOptions,BrowserCookieOptions,ConcurrentFragmentsOptions,ModeOptions) — статические спискиChoiceItem<T>, объявленные прямо в VM.- Настройки персистятся через
PersistSettings()при каждом изменении соответствующего свойства (папка, режим, разрешение, cookies-браузер,ConcurrentFragments, playlist-флаг, тема). MainWindow.xaml— чистый биндинг, вся логика в VM. Карточка «Параметры сохранения» — самое вероятное место для новых пользовательских настроек скачивания.
Тесты (YT_downloader.Tests/)
MSTest, без моков UI/процессов — тестируются чистые функции:
YtDlpServiceArgumentTests—BuildAnalyzeArguments/BuildDownloadArguments/NormalizeYouTubeUrl/ детекторы ошибок (403, bot-verification). При добавлении нового флага yt-dlp — добавляй сюда тест на его наличие/отсутствие по условию (см.ConcurrentFragments_AreOnlyAddedWhenGreaterThanOne).YtDlpProgressParserTests,YtDlpMetadataParserTests,DownloadProgressAggregatorTests,DisplayModelTests.
Запуск: dotnet test .\YT_downloader\YT_downloader.slnx.
Частые точки изменений и на что обратить внимание
- Новая опция скачивания, видимая пользователю (как
ConcurrentFragments) обычно требует правки в 5 местах:DownloadRequest→YtDlpService.BuildDownloadArguments→AppSettings→MainViewModel(список опций + свойство + передача вDownloadRequest+ запись вPersistSettings) →MainWindow.xaml(ComboBox). Плюс тест вYtDlpServiceArgumentTests. - Прогресс-шаблон (
ProgressTemplateвYtDlpService) и его порядок полей жёстко завязаны на порядковый парсинг вYtDlpProgressParser.TryParseTemplate/TryParseDetailedTemplate— менять их можно только синхронно. Tools/*.exeне в Git (исключены правилом*.exe) — при локальной разработке их нужно положить вручную (см. README «Подготовка каталога Tools»), иначеEnsureToolsброситYtDlpErrorKind.ToolMissing/FfmpegMissing.- Скачивание всего плейлиста — по явному флажку
DownloadPlaylist; по умолчанию ссылка на плейлист внутри видео обрабатывается как одно видео (--no-playlist). - Приложение никогда не строит команду как строку и не вызывает
cmd.exe— аргументы всегда черезProcessStartInfo.ArgumentList. Сохраняй этот инвариант при любых изменениях вYtDlpService.
Постоянное правило: синхронизация CLAUDE.md и AGENTS.md
AGENTS.md в корне репозитория — полный дубликат этого файла (тот же формат, тот же контент).
Любое изменение этого файла должно сразу же зеркалироваться в AGENTS.md, и наоборот.
Если найдено расхождение между файлами — считать это ошибкой, актуальным источником считать более
свежий по содержанию (не по дате модификации) и синхронизировать оба файла в тот же коммит/правку.
