package main import ( "bufio" "fmt" "io" "log" "os" "os/exec" "strings" "time" "github.com/kkdai/youtube/v2" ) const OUTPUT_DIR = "C:/Users/Administrator/ytdlpVideos" const STUCK_TIMEOUT = time.Duration(60)*time.Second func DownloadNative(event PBEvent, status chan error) { log.Printf("%s: Downloading %s", event.Record.Id, event.Record.Link) videoId := strings.Split(event.Record.Link, "?v=")[1] client := youtube.Client{} video, err := client.GetVideo(videoId) if err != nil { status <- err return } formats := video.Formats.WithAudioChannels() stream, _, err := client.GetStream(video, &formats[0]) if err != nil { status <- err return } defer stream.Close() log.Printf("%s: Video title: %s", event.Record.Id, video.Title) outFolder := fmt.Sprintf("%s/%s", OUTPUT_DIR, video.Author) out := fmt.Sprintf("%s/%s.mp4", outFolder, video.Title) err = os.MkdirAll(outFolder, os.ModePerm) if err != nil { status <- err return } log.Printf("%s: Video save location: %s", event.Record.Id, out) file, err := os.Create(out) if err != nil { status <- err return } defer file.Close() _, err = io.Copy(file, stream) if err != nil { status <- err return } } func Download(event PBEvent, status chan error) { cmd := exec.Command("yt-dlp", "-v", "--mark-watched", "--color", "never", "-r", "50M", "--http-chunk-size", "20M", "-o", "C:/Users/Administrator/ytdlpVideos/%(title)s.%(ext)s", "-f", "bestvideo[ext=mp4]+bestaudio[ext=m4a]", event.Record.Link) // Get the pipes for stdout and stderr stdout, err := cmd.StdoutPipe() if err != nil { log.Printf("Error creating StdoutPipe: %++v for cmd %++v", err, cmd) status <- err return } stderr, err := cmd.StderrPipe() if err != nil { log.Printf("Error creating StderrPipe: %++v for cmd %++v", err, cmd) status <- err return } err = cmd.Start() if err != nil { log.Printf("Error starting command: %++v with error %++v", cmd, err) status <- err return } lastMessage := time.Now() stdoutScanner := bufio.NewScanner(stdout) go func() { for stdoutScanner.Scan() { lastMessage = time.Now() log.Printf("%s: %s", event.Record.Id, stdoutScanner.Text()) } }() stderrScanner := bufio.NewScanner(stderr) go func() { for stderrScanner.Scan() { lastMessage = time.Now() log.Printf("%s: %s", event.Record.Id, stderrScanner.Text()) } }() go func() { for { if time.Since(lastMessage) > STUCK_TIMEOUT { log.Printf("Command timed out, killing process") err := cmd.Process.Kill() if err != nil { log.Printf("Error killing process: %v", err) } status <- fmt.Errorf("command timed out") return } time.Sleep(time.Second) } }() err = cmd.Wait() if err != nil { exitError, ok := err.(*exec.ExitError) if ok { exitCode := exitError.ExitCode() log.Printf("Command exited with code %d", exitCode) } else { log.Printf("Error running yt-dlp: %++v; %++v", cmd, err) return } } else { log.Printf("Downloaded %s (%s)", event.Record.Id, event.Record.Link) SetDownloaded(event) } }