2023-08-20 11:22:32 +02:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"os/exec"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/jedib0t/go-pretty/v6/progress"
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
const YT_DLP string = "yt-dlp"
|
|
|
|
const YT_DLP_FLAG_GET_TITLE string = "--get-title"
|
|
|
|
|
|
|
|
const JOB_STATUS_NEW = 1
|
|
|
|
const JOB_STATUS_COMPLETED = 2
|
|
|
|
const JOB_STATUS_ERR = 3
|
|
|
|
|
|
|
|
type DownloadCtx struct {
|
|
|
|
link string
|
|
|
|
title string
|
|
|
|
progress uint8
|
|
|
|
status uint8
|
|
|
|
tracker *progress.Tracker
|
|
|
|
err *error
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func Download(links *[]string) {
|
|
|
|
// Start and manage goroutines here
|
|
|
|
downloadCtxsChan := make(chan *DownloadCtx)
|
2023-08-20 16:25:29 +02:00
|
|
|
var jobs []DownloadCtx
|
|
|
|
|
2023-08-20 11:22:32 +02:00
|
|
|
startedGoRoutines := 0
|
|
|
|
pw := progress.NewWriter()
|
2023-08-20 16:25:29 +02:00
|
|
|
pw.SetStyle(progress.StyleDefault)
|
2023-08-20 11:22:32 +02:00
|
|
|
pw.SetTrackerLength(10)
|
|
|
|
pw.SetNumTrackersExpected(len(*links))
|
|
|
|
pw.SetUpdateFrequency(time.Millisecond * 100)
|
2023-08-20 16:25:29 +02:00
|
|
|
pw.Style().Colors = progress.StyleColorsExample
|
|
|
|
pw.SetTrackerPosition(progress.PositionLeft)
|
2023-08-20 11:22:32 +02:00
|
|
|
pw.Style().Visibility.ETA = false
|
2023-08-20 16:25:29 +02:00
|
|
|
pw.Style().Visibility.ETAOverall = false
|
2023-08-20 11:22:32 +02:00
|
|
|
pw.Style().Visibility.Speed = false
|
|
|
|
pw.Style().Visibility.Percentage = false
|
|
|
|
pw.Style().Visibility.Value = false
|
|
|
|
pw.Style().Visibility.TrackerOverall = true
|
2023-08-20 16:25:29 +02:00
|
|
|
pw.Style().Options.TimeInProgressPrecision = time.Second
|
|
|
|
pw.Style().Options.TimeDonePrecision = time.Second
|
2023-08-20 11:22:32 +02:00
|
|
|
|
|
|
|
go pw.Render()
|
|
|
|
|
|
|
|
for _, val := range *links {
|
|
|
|
ctx := createDownloadCtx(val)
|
|
|
|
|
2023-08-20 16:25:29 +02:00
|
|
|
jobs = append(jobs, *ctx)
|
|
|
|
|
2023-08-20 11:22:32 +02:00
|
|
|
pw.AppendTracker(ctx.tracker)
|
|
|
|
|
2023-08-20 16:25:29 +02:00
|
|
|
go startJob(ctx, downloadCtxsChan)
|
2023-08-20 11:22:32 +02:00
|
|
|
startedGoRoutines++
|
|
|
|
}
|
|
|
|
|
2023-08-20 16:25:29 +02:00
|
|
|
for i := 0; i < startedGoRoutines; i++ {
|
|
|
|
ctx := <- downloadCtxsChan
|
|
|
|
if ctx.err != nil {
|
2023-08-20 11:22:32 +02:00
|
|
|
ctx.tracker.MarkAsErrored()
|
2023-08-20 16:25:29 +02:00
|
|
|
} else {
|
|
|
|
ctx.tracker.MarkAsDone()
|
|
|
|
}
|
2023-08-20 11:22:32 +02:00
|
|
|
}
|
|
|
|
|
2023-08-20 16:25:29 +02:00
|
|
|
time.Sleep(time.Millisecond * 100)
|
2023-08-20 11:22:32 +02:00
|
|
|
pw.Stop()
|
|
|
|
for pw.IsRenderInProgress() {}
|
2023-08-20 16:25:29 +02:00
|
|
|
|
2023-08-20 11:22:32 +02:00
|
|
|
}
|
|
|
|
|
2023-08-20 16:25:29 +02:00
|
|
|
func createDownloadCtx(link string) *DownloadCtx {
|
2023-08-20 11:22:32 +02:00
|
|
|
var ctx DownloadCtx
|
|
|
|
ctx.tracker = &progress.Tracker{}
|
|
|
|
ctx.tracker.SetValue(0)
|
|
|
|
ctx.tracker.Message = link
|
|
|
|
ctx.tracker.Units = progress.UnitsDefault
|
|
|
|
ctx.link = link
|
|
|
|
ctx.status = JOB_STATUS_NEW
|
2023-08-20 16:25:29 +02:00
|
|
|
return &ctx
|
2023-08-20 11:22:32 +02:00
|
|
|
}
|
|
|
|
|
2023-08-20 16:25:29 +02:00
|
|
|
func startJob(ctx *DownloadCtx, downloadCtxs chan *DownloadCtx) {
|
2023-08-20 11:22:32 +02:00
|
|
|
|
2023-09-22 01:08:35 +02:00
|
|
|
c := make(chan int)
|
|
|
|
go func(c chan int) {
|
|
|
|
getTitle(ctx)
|
2023-08-20 11:22:32 +02:00
|
|
|
|
2023-09-22 01:08:35 +02:00
|
|
|
if ctx.err != nil {
|
|
|
|
downloadCtxs <- ctx
|
|
|
|
return
|
|
|
|
}
|
|
|
|
ctx.tracker.UpdateMessage(ctx.title)
|
|
|
|
c <- 0
|
|
|
|
}(c)
|
2023-08-20 11:22:32 +02:00
|
|
|
|
2023-08-20 16:25:29 +02:00
|
|
|
ytdlpDownload(ctx, downloadCtxs)
|
2023-08-20 11:22:32 +02:00
|
|
|
|
2023-09-22 01:08:35 +02:00
|
|
|
<- c // Ensure to return only after
|
2023-08-20 11:22:32 +02:00
|
|
|
downloadCtxs <- ctx
|
|
|
|
}
|
2023-08-20 16:25:29 +02:00
|
|
|
|
|
|
|
func getTitle(ctx *DownloadCtx) {
|
2023-08-20 11:22:32 +02:00
|
|
|
|
|
|
|
cmd := exec.Command(YT_DLP, YT_DLP_FLAG_GET_TITLE, ctx.link)
|
|
|
|
stdout, err := cmd.Output()
|
|
|
|
if err != nil {
|
|
|
|
ctx.err = &err
|
|
|
|
ctx.status = JOB_STATUS_ERR
|
|
|
|
return
|
|
|
|
}
|
|
|
|
title := string(stdout)
|
|
|
|
title = strings.TrimSpace(title)
|
|
|
|
ctx.title = title
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
func ytdlpDownload(
|
2023-08-20 16:25:29 +02:00
|
|
|
ctx *DownloadCtx, downloadCtxs chan *DownloadCtx) {
|
2023-08-20 11:22:32 +02:00
|
|
|
|
|
|
|
cmd := exec.Command(YT_DLP, ctx.link)
|
2023-08-20 13:50:42 +02:00
|
|
|
_, err := cmd.Output()
|
2023-08-20 11:22:32 +02:00
|
|
|
if err != nil {
|
|
|
|
ctx.err = &err
|
|
|
|
ctx.status = JOB_STATUS_ERR
|
2023-08-20 16:25:29 +02:00
|
|
|
downloadCtxs <- ctx
|
2023-08-20 11:22:32 +02:00
|
|
|
return
|
|
|
|
}
|
2023-08-20 16:25:29 +02:00
|
|
|
ctx.status = JOB_STATUS_COMPLETED
|
|
|
|
|
2023-08-20 11:22:32 +02:00
|
|
|
}
|