init: working multi download
This commit is contained in:
commit
8d983de8ef
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
yt-mdl
|
140
downloader.go
Normal file
140
downloader.go
Normal file
@ -0,0 +1,140 @@
|
||||
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
|
||||
// Now get titles only
|
||||
downloadCtxsChan := make(chan *DownloadCtx)
|
||||
getTitleErrChan := make(chan *DownloadCtx)
|
||||
startedGoRoutines := 0
|
||||
pw := progress.NewWriter()
|
||||
pw.SetTrackerLength(10)
|
||||
pw.SetNumTrackersExpected(len(*links))
|
||||
pw.SetStyle(progress.StyleDefault)
|
||||
pw.SetUpdateFrequency(time.Millisecond * 100)
|
||||
pw.Style().Visibility.ETA = false
|
||||
pw.Style().Colors = progress.StyleColorsExample
|
||||
pw.Style().Visibility.Speed = false
|
||||
pw.Style().Visibility.Percentage = false
|
||||
pw.Style().Visibility.Value = false
|
||||
pw.Style().Visibility.TrackerOverall = true
|
||||
|
||||
go pw.Render()
|
||||
|
||||
for _, val := range *links {
|
||||
ctx := createDownloadCtx(val)
|
||||
|
||||
pw.AppendTracker(ctx.tracker)
|
||||
|
||||
go startJob(&ctx, downloadCtxsChan, getTitleErrChan)
|
||||
startedGoRoutines++
|
||||
}
|
||||
|
||||
for startedGoRoutines > 0 {
|
||||
select {
|
||||
case ctx := <- downloadCtxsChan:
|
||||
ctx.tracker.UpdateMessage(ctx.title)
|
||||
startedGoRoutines--
|
||||
|
||||
case ctx := <- getTitleErrChan:
|
||||
ctx.tracker.MarkAsErrored()
|
||||
startedGoRoutines--
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pw.Stop()
|
||||
|
||||
for pw.IsRenderInProgress() {}
|
||||
}
|
||||
|
||||
func createDownloadCtx(link string) DownloadCtx {
|
||||
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
|
||||
return ctx
|
||||
}
|
||||
|
||||
func startJob(
|
||||
ctx *DownloadCtx, downloadCtxs chan *DownloadCtx, errs chan *DownloadCtx) {
|
||||
|
||||
getTitle(ctx)
|
||||
|
||||
if ctx.err != nil {
|
||||
errs <- ctx
|
||||
return
|
||||
}
|
||||
ctx.tracker.UpdateMessage(ctx.title)
|
||||
|
||||
ytdlpDownload(ctx, downloadCtxs, errs)
|
||||
|
||||
if ctx.err != nil {
|
||||
errs <- ctx
|
||||
return
|
||||
}
|
||||
|
||||
downloadCtxs <- ctx
|
||||
}
|
||||
func getTitle(
|
||||
ctx *DownloadCtx) {
|
||||
|
||||
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(
|
||||
ctx *DownloadCtx, downloadCtxs chan *DownloadCtx, errs chan *DownloadCtx) {
|
||||
|
||||
cmd := exec.Command(YT_DLP, ctx.link)
|
||||
stdout, err := cmd.Output()
|
||||
if err != nil {
|
||||
ctx.err = &err
|
||||
ctx.status = JOB_STATUS_ERR
|
||||
errs <- ctx
|
||||
return
|
||||
}
|
||||
title := string(stdout)
|
||||
title = strings.TrimSpace(title)
|
||||
ctx.title = title
|
||||
|
||||
downloadCtxs <- ctx
|
||||
|
||||
}
|
11
go.mod
Normal file
11
go.mod
Normal file
@ -0,0 +1,11 @@
|
||||
module github.com/HeshamTB/yt-mdl
|
||||
|
||||
go 1.21.0
|
||||
|
||||
require github.com/jedib0t/go-pretty/v6 v6.4.6
|
||||
|
||||
require (
|
||||
github.com/mattn/go-runewidth v0.0.13 // indirect
|
||||
github.com/rivo/uniseg v0.2.0 // indirect
|
||||
golang.org/x/sys v0.1.0 // indirect
|
||||
)
|
23
go.sum
Normal file
23
go.sum
Normal file
@ -0,0 +1,23 @@
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/jedib0t/go-pretty/v6 v6.4.6 h1:v6aG9h6Uby3IusSSEjHaZNXpHFhzqMmjXcPq1Rjl9Jw=
|
||||
github.com/jedib0t/go-pretty/v6 v6.4.6/go.mod h1:Ndk3ase2CkQbXLLNf5QDHoYb6J9WtVfmHZu9n8rk2xs=
|
||||
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
|
||||
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/pkg/profile v1.6.0/go.mod h1:qBsxPvzyUincmltOk6iyRVxHYg4adc0OFOv72ZdLa18=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.4 h1:wZRexSlwd7ZXfKINDLsO4r7WBt3gTKONc6K/VesHvHM=
|
||||
github.com/stretchr/testify v1.7.4/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
52
yt-mdl.go
Normal file
52
yt-mdl.go
Normal file
@ -0,0 +1,52 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
var verbose bool
|
||||
var videoLinks []string
|
||||
var maxConcurrent int
|
||||
|
||||
func init() {
|
||||
flag.BoolVar(&verbose, "verbose", false, "Be verbose")
|
||||
flag.IntVar(&maxConcurrent, "goroutines", 8, "Maximum concurrent downloads")
|
||||
}
|
||||
|
||||
func main() {
|
||||
parseArgs()
|
||||
|
||||
fmt.Println("Links to be downloaded ", videoLinks)
|
||||
|
||||
Download(&videoLinks)
|
||||
|
||||
}
|
||||
|
||||
func parseArgs() {
|
||||
flag.Parse()
|
||||
for _, arg := range flag.Args(){
|
||||
if !isValidURL(arg) {
|
||||
fmt.Println("Skipping ", arg)
|
||||
continue
|
||||
}
|
||||
videoLinks = append(videoLinks, arg)
|
||||
}
|
||||
}
|
||||
|
||||
func isValidURL(str string) bool {
|
||||
_, err := url.ParseRequestURI(str)
|
||||
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
u, err := url.Parse(str)
|
||||
|
||||
if err != nil || u.Scheme != "https" {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
Loading…
Reference in New Issue
Block a user