Skip to content

feat(phase-3): add yt-dlp downloader implementation#5

Merged
amirmalekian merged 5 commits into
mainfrom
feat/ytdlp-adapter
Jul 19, 2026
Merged

feat(phase-3): add yt-dlp downloader implementation#5
amirmalekian merged 5 commits into
mainfrom
feat/ytdlp-adapter

Conversation

@amirmalekian

Copy link
Copy Markdown
Owner

Overview

This PR implements the first feature of Phase 3 (Download Engine) by adding a production-ready yt-dlp based downloader implementation.

The existing Downloader abstraction is now backed by a real downloader implementation while keeping the interface unchanged.

Changes

Downloader Implementation

  • Added YTDLPDownloader
  • Added yt-dlp command execution through a testable command runner abstraction
  • Added metadata extraction from yt-dlp JSON output
  • Added context cancellation support
  • Added configurable download timeout handling
  • Added result mapping from yt-dlp output into internal downloader types

Testing

Added isolated unit tests covering:

  • successful download flow
  • metadata parsing
  • invalid JSON handling
  • command execution failures
  • context cancellation
  • result parsing

Added separate integration tests for environments with yt-dlp installed.

Documentation

Updated docs/ROADMAP.md:

  • Marked yt-dlp Adapter as completed
  • Kept Playlist Support and Progress Reporting as remaining Phase 3 tasks

Out of Scope

This PR does not include:

  • playlist parsing
  • worker pool integration
  • download queue changes
  • progress callbacks
  • real-time download statistics

These will be handled in following Phase 3 features.

Verification

Passed:

go test ./...
golangci-lint run ./...
go build ./...

@amirmalekian
amirmalekian requested a review from Copilot July 19, 2026 08:50
@amirmalekian
amirmalekian merged commit d37aaba into main Jul 19, 2026
4 checks passed
@amirmalekian
amirmalekian deleted the feat/ytdlp-adapter branch July 19, 2026 08:52

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a concrete Phase 3 “Download Engine” implementation by introducing a yt-dlp–backed downloader and accompanying unit/integration tests, while extending downloader types to include metadata.

Changes:

  • Added YTDLPDownloader that shells out to yt-dlp, supports context cancellation, and maps yt-dlp JSON into internal result/metadata types.
  • Added unit tests using a fake command runner plus integration tests that run when yt-dlp is available.
  • Updated Phase 3 roadmap status and added a Metadata type to the downloader package.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
internal/downloader/ytdlp.go New yt-dlp based downloader implementation (command runner abstraction, download + metadata fetch, result parsing).
internal/downloader/ytdlp_test.go Unit tests for download flow, parsing, error paths, and cancellation using a fake runner.
internal/downloader/ytdlp_integration_test.go Integration tests that exercise yt-dlp against a real URL when available.
internal/downloader/types.go Adds Metadata type alongside existing Item/Result/Downloader.
docs/ROADMAP.md Marks yt-dlp adapter as completed and updates Phase 3 checklist.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +116 to +118
if expectedID != "" && info.ID != expectedID {
continue
}
Comment on lines +91 to +97
func (d *YTDLPDownloader) parseResult(expectedID string) (Result, error) {
// TODO: This method scans the output directory which is not safe for concurrent downloads.
// Consider using a unique temp directory per download or returning the file path directly from yt-dlp.
entries, err := os.ReadDir(d.outputDir)
if err != nil {
return Result{}, err
}
Comment on lines +168 to +174
output, err := d.cmdRunner.Run(ctx, "yt-dlp", args...)
if err != nil {
if ctx.Err() == context.Canceled || ctx.Err() == context.DeadlineExceeded {
return nil, fmt.Errorf("metadata fetch cancelled: %w", ctx.Err())
}
return nil, fmt.Errorf("yt-dlp metadata failed: %w", err)
}
@@ -0,0 +1,118 @@
package downloader
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants