package main import ( "context" "flag" "fmt" "io" "log" "net/http" "os" "strings" "sync" "time" "git.netflux.io/rob/clipper/youtube" youtubev2 "github.com/kkdai/youtube/v2" ) func main() { var ( verbose bool printMode bool downloadMode bool audioOnly bool videoOnly bool ) flag.BoolVar(&verbose, "v", false, "verbose output") flag.BoolVar(&printMode, "print", true, "print format info") flag.BoolVar(&downloadMode, "download", false, "download all media to ./debug") flag.BoolVar(&audioOnly, "audio", false, "only print audio formats") flag.BoolVar(&videoOnly, "video", false, "only print video formats") flag.Parse() videoID := flag.Arg(0) ctx := context.Background() var youtubeClient youtubev2.Client video, err := youtubeClient.GetVideoContext(ctx, videoID) if err != nil { log.Fatal(err) } formats := video.Formats if downloadMode { downloadAll(formats) return } switch { case audioOnly: formats = youtube.SortAudio(formats) case videoOnly: formats = youtube.SortVideo(formats) } fmt.Println("In descending order of preference:") for n, f := range formats { fmt.Printf("%d: %s\n", n+1, youtube.FormatDebugString(&f, verbose)) } } func downloadAll(formats youtubev2.FormatList) { var wg sync.WaitGroup for i := range formats { format := formats[i] wg.Add(1) go func() { defer wg.Done() start := time.Now() outpath := fmt.Sprintf("./debug/%s.%s-itag-%d", strings.ReplaceAll(format.MimeType, "/", "'"), format.Quality, format.ItagNo) output, err := os.Create(outpath) if err != nil { log.Fatalf("error opening output file: %v", err) } resp, err := http.Get(format.URL) if err != nil { log.Fatalf("error fetching media: %v", err) } defer resp.Body.Close() n, err := io.Copy(output, resp.Body) if err != nil { log.Fatalf("error reading media: %v", err) } dur := time.Since(start) log.Printf("downloaded itag %d, %d bytes in %v secs", format.ItagNo, n, dur.Seconds()) }() } wg.Wait() }