Skip to content

Commit 99cd40a

Browse files
committed
adding resume capability
Signed-off-by: abzcoding <[email protected]>
1 parent ff8e088 commit 99cd40a

File tree

6 files changed

+139
-111
lines changed

6 files changed

+139
-111
lines changed

Makefile

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@ COMMIT = $$(git describe --always)
22

33
deps:
44
@echo "====> Install dependencies..."
5-
go get -d github.com/fatih/color
6-
go get -d github.com/mattn/go-colorable
7-
go get -d github.com/mattn/go-isatty
8-
go get -d github.com/fatih/color
9-
go get -d gopkg.in/cheggaaa/pb.v1
10-
go get -d github.com/mattn/go-isatty
11-
go get -d github.com/imkira/go-task
12-
go get -d github.com/fujiwara/shapeio
13-
go get -d github.com/alecthomas/units
5+
go get github.com/fatih/color
6+
go get github.com/mattn/go-colorable
7+
go get github.com/mattn/go-isatty
8+
go get github.com/fatih/color
9+
go get gopkg.in/cheggaaa/pb.v1
10+
go get github.com/mattn/go-isatty
11+
go get github.com/imkira/go-task
12+
go get github.com/fujiwara/shapeio
13+
go get github.com/alecthomas/units
1414

1515
clean:
1616
@echo "====> Remove installed binary"

README.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
### Install
1717

1818
```bash
19-
$ go get -d github.com/abzcoding/hget
19+
$ go get github.com/abzcoding/hget
2020
$ cd $GOPATH/src/github.com/abzcoding/hget
2121
$ make clean install
2222
```
@@ -33,6 +33,11 @@ hget -proxy "127.0.0.1:12345" URL # to download using socks5 proxy
3333
hget -proxy "http://sample-proxy.com:8080" URL # to download using http proxy
3434
hget -file sample.txt # to download a list of urls
3535
hget -n 4 -rate 100KB URL # to download using 4 threads & limited to 100KB per second
36+
37+
# real world example
38+
hget -n 16 -rate 10MiB "https://releases.ubuntu.com/24.04.1/ubuntu-24.04.1-desktop-amd64.iso"
39+
# resuming a stopped download
40+
hget -resume "ubuntu-24.04.1-desktop-amd64.iso"
3641
```
3742

3843
### Help
@@ -62,5 +67,3 @@ To interrupt any on-downloading process, just ctrl-c or ctrl-d at the middle of
6267

6368
### Resume
6469
![](https://i.gyazo.com/caa69808f6377421cb2976f323768dc4.gif)
65-
66-

go.mod

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,21 @@
11
module github.com/abzcoding/hget
22

3-
go 1.16
3+
go 1.23
44

55
require (
6-
github.com/alecthomas/units v0.0.0-20210208195552-ff826a37aa15
7-
github.com/fatih/color v1.12.0
6+
github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b
7+
github.com/fatih/color v1.18.0
88
github.com/fujiwara/shapeio v1.0.0
99
github.com/imkira/go-task v1.0.0
10-
github.com/mattn/go-colorable v0.1.8
11-
github.com/mattn/go-isatty v0.0.13
12-
github.com/mattn/go-runewidth v0.0.13 // indirect
13-
golang.org/x/net v0.0.0-20210614182718-04defd469f4e
10+
github.com/mattn/go-colorable v0.1.14
11+
github.com/mattn/go-isatty v0.0.20
12+
golang.org/x/net v0.35.0
1413
gopkg.in/cheggaaa/pb.v1 v1.0.28
1514
)
15+
16+
require (
17+
github.com/mattn/go-runewidth v0.0.16 // indirect
18+
github.com/rivo/uniseg v0.4.7 // indirect
19+
golang.org/x/sys v0.30.0 // indirect
20+
golang.org/x/time v0.10.0 // indirect
21+
)

go.sum

Lines changed: 32 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,47 @@
1-
github.com/alecthomas/units v0.0.0-20210208195552-ff826a37aa15 h1:AUNCr9CiJuwrRYS3XieqF+Z9B9gNxo/eANAJCF2eiN4=
2-
github.com/alecthomas/units v0.0.0-20210208195552-ff826a37aa15/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
3-
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
1+
github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b h1:mimo19zliBX/vSQ6PWWSL9lK8qwHozUj03+zLoEB8O0=
2+
github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b/go.mod h1:fvzegU4vN3H1qMT+8wDmzjAcDONcgo2/SZ/TyfdUOFs=
43
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
4+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
5+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
56
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
67
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
7-
github.com/fatih/color v1.12.0 h1:mRhaKNwANqRgUBGKmnI5ZxEk7QXmjQeCcuYFMX2bfcc=
8-
github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
8+
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
9+
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
910
github.com/fujiwara/shapeio v1.0.0 h1:xG5D9oNqCSUUbryZ/jQV3cqe1v2suEjwPIcEg1gKM8M=
1011
github.com/fujiwara/shapeio v1.0.0/go.mod h1:LmEmu6L/8jetyj1oewewFb7bZCNRwE7wLCUNzDLaLVA=
1112
github.com/imkira/go-task v1.0.0 h1:r8RN5nLcmVpYf/UB28d1w4XApVxDntWLAsiExNIptsY=
1213
github.com/imkira/go-task v1.0.0/go.mod h1:xU9xcPxKeBOQTwx8ILmT8xLxrm/SFmyBhPO8SlCRyRI=
13-
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
14-
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
15-
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
16-
github.com/mattn/go-isatty v0.0.13 h1:qdl+GuBjcsKKDco5BsxPJlId98mSWNKqYA+Co0SC1yA=
17-
github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
18-
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
19-
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
14+
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
15+
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
16+
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
17+
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
18+
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
19+
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
2020
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
2121
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
22-
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
2322
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
23+
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
24+
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
2425
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
25-
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
26-
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
27-
golang.org/x/net v0.0.0-20210614182718-04defd469f4e h1:XpT3nA5TvE525Ne3hInMh6+GETgn27Zfm9dxsThnX2Q=
28-
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
29-
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
30-
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
31-
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
32-
golang.org/x/sys v0.0.0-20210423082822-04245dca01da h1:b3NXsE2LusjYGGjL5bxEVZZORm/YEFFrWFjR8eFrw/c=
33-
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
34-
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
35-
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
36-
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE=
26+
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
27+
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
28+
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
29+
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
30+
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
31+
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
32+
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
33+
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
34+
golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
35+
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
36+
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
37+
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
38+
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
3739
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
38-
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
40+
golang.org/x/time v0.10.0 h1:3usCWA8tQn0L8+hFJQNgzpWbd89begxN66o1Ojdn5L4=
41+
golang.org/x/time v0.10.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
3942
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
4043
gopkg.in/cheggaaa/pb.v1 v1.0.28 h1:n1tBJnnK2r7g9OW2btFH91V92STTUevLXYFb8gy9EMk=
4144
gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
42-
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
43-
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
45+
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
46+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
47+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

main.go

Lines changed: 55 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -16,79 +16,65 @@ import (
1616
var displayProgress = true
1717

1818
func main() {
19-
var err error
20-
var proxy, filepath, bwLimit string
19+
// var err error
20+
var proxy, filePath, bwLimit, resumeTask string
2121

22-
conn := flag.Int("n", runtime.NumCPU(), "connection")
23-
skiptls := flag.Bool("skip-tls", true, "skip verify certificate for https")
24-
flag.StringVar(&proxy, "proxy", "", "proxy for downloading, ex \n\t-proxy '127.0.0.1:12345' for socks5 proxy\n\t-proxy 'http://proxy.com:8080' for http proxy")
25-
flag.StringVar(&filepath, "file", "", "filepath that contains links in each line")
26-
flag.StringVar(&bwLimit, "rate", "", "bandwidth limit to use while downloading, ex\n\t -rate 10kB\n\t-rate 10MiB")
22+
conn := flag.Int("n", runtime.NumCPU(), "number of connections")
23+
skiptls := flag.Bool("skip-tls", true, "skip certificate verification for https")
24+
flag.StringVar(&proxy, "proxy", "", "proxy for downloading, e.g. -proxy '127.0.0.1:12345' for socks5 or -proxy 'http://proxy.com:8080' for http proxy")
25+
flag.StringVar(&filePath, "file", "", "path to a file that contains one URL per line")
26+
flag.StringVar(&bwLimit, "rate", "", "bandwidth limit during download, e.g. -rate 10kB or -rate 10MiB")
27+
flag.StringVar(&resumeTask, "resume", "", "resume download task with given task name (or URL)")
2728

2829
flag.Parse()
2930
args := flag.Args()
31+
32+
// If the resume flag is provided, use that path (ignoring other arguments)
33+
if resumeTask != "" {
34+
state, err := Resume(resumeTask)
35+
FatalCheck(err)
36+
Execute(state.URL, state, *conn, *skiptls, proxy, bwLimit)
37+
return
38+
}
39+
40+
// If no resume flag, then check for positional URL or file input
3041
if len(args) < 1 {
31-
if len(filepath) < 2 {
32-
Errorln("url is required")
42+
if len(filePath) < 1 {
43+
Errorln("A URL or input file with URLs is required")
3344
usage()
3445
os.Exit(1)
3546
}
36-
// Creating a SerialGroup.
47+
// Create a serial group for processing multiple URLs in a file.
3748
g1 := task.NewSerialGroup()
38-
file, err := os.Open(filepath)
49+
file, err := os.Open(filePath)
3950
if err != nil {
4051
FatalCheck(err)
4152
}
42-
4353
defer file.Close()
4454

4555
reader := bufio.NewReader(file)
46-
4756
for {
4857
line, _, err := reader.ReadLine()
49-
5058
if err == io.EOF {
5159
break
5260
}
53-
54-
g1.AddChild(downloadTask(string(line), nil, *conn, *skiptls, proxy, bwLimit))
61+
url := string(line)
62+
// Add the download task for each URL
63+
g1.AddChild(downloadTask(url, nil, *conn, *skiptls, proxy, bwLimit))
5564
}
5665
g1.Run(nil)
5766
return
5867
}
5968

60-
command := args[0]
61-
if command == "tasks" {
62-
if err = TaskPrint(); err != nil {
63-
Errorf("%v\n", err)
64-
}
65-
return
66-
} else if command == "resume" {
67-
if len(args) < 2 {
68-
Errorln("downloading task name is required")
69-
usage()
70-
os.Exit(1)
71-
}
72-
73-
var task string
74-
if IsURL(args[1]) {
75-
task = TaskFromURL(args[1])
76-
} else {
77-
task = args[1]
78-
}
79-
80-
state, err := Resume(task)
69+
// Otherwise, if a URL is provided as positional argument, treat it as a new download.
70+
downloadURL := args[0]
71+
// Check if a folder already exists for the task and remove if necessary.
72+
if ExistDir(FolderOf(downloadURL)) {
73+
Warnf("Downloading task already exists, remove it first \n")
74+
err := os.RemoveAll(FolderOf(downloadURL))
8175
FatalCheck(err)
82-
Execute(state.URL, state, *conn, *skiptls, proxy, bwLimit)
83-
return
84-
} else {
85-
if ExistDir(FolderOf(command)) {
86-
Warnf("Downloading task already exist, remove first \n")
87-
err := os.RemoveAll(FolderOf(command))
88-
FatalCheck(err)
89-
}
90-
Execute(command, nil, *conn, *skiptls, proxy, bwLimit)
9176
}
77+
Execute(downloadURL, nil, *conn, *skiptls, proxy, bwLimit)
9278
}
9379

9480
func downloadTask(url string, state *State, conn int, skiptls bool, proxy string, bwLimit string) task.Task {
@@ -98,19 +84,16 @@ func downloadTask(url string, state *State, conn int, skiptls bool, proxy string
9884
return task.NewTaskWithFunc(run)
9985
}
10086

101-
// Execute configures the HTTPDownloader and uses it to download stuff.
87+
// Execute configures the HTTPDownloader and uses it to download the target.
10288
func Execute(url string, state *State, conn int, skiptls bool, proxy string, bwLimit string) {
103-
//otherwise is hget <URL> command
104-
89+
// Capture OS interrupt signals
10590
signalChan := make(chan os.Signal, 1)
10691
signal.Notify(signalChan,
10792
syscall.SIGHUP,
10893
syscall.SIGINT,
10994
syscall.SIGTERM,
11095
syscall.SIGQUIT)
11196

112-
//set up parallel
113-
11497
var files = make([]string, 0)
11598
var parts = make([]Part, 0)
11699
var isInterrupted = false
@@ -125,14 +108,20 @@ func Execute(url string, state *State, conn int, skiptls bool, proxy string, bwL
125108
if state == nil {
126109
downloader = NewHTTPDownloader(url, conn, skiptls, proxy, bwLimit)
127110
} else {
128-
downloader = &HTTPDownloader{url: state.URL, file: filepath.Base(state.URL), par: int64(len(state.Parts)), parts: state.Parts, resumable: true}
111+
downloader = &HTTPDownloader{
112+
url: state.URL,
113+
file: filepath.Base(state.URL),
114+
par: int64(len(state.Parts)),
115+
parts: state.Parts,
116+
resumable: true,
117+
}
129118
}
130119
go downloader.Do(doneChan, fileChan, errorChan, interruptChan, stateChan)
131120

132121
for {
133122
select {
134123
case <-signalChan:
135-
//send par number of interrupt for each routine
124+
// Signal all active download routines to interrupt.
136125
isInterrupted = true
137126
for i := 0; i < conn; i++ {
138127
interruptChan <- true
@@ -141,19 +130,19 @@ func Execute(url string, state *State, conn int, skiptls bool, proxy string, bwL
141130
files = append(files, file)
142131
case err := <-errorChan:
143132
Errorf("%v", err)
144-
panic(err) //maybe need better style
133+
panic(err)
145134
case part := <-stateChan:
146135
parts = append(parts, part)
147136
case <-doneChan:
148137
if isInterrupted {
149138
if downloader.resumable {
150-
Printf("Interrupted, saving state ... \n")
139+
Printf("Interrupted, saving state...\n")
151140
s := &State{URL: url, Parts: parts}
152141
if err := s.Save(); err != nil {
153142
Errorf("%v\n", err)
154143
}
155144
} else {
156-
Warnf("Interrupted, but downloading url is not resumable, silently die")
145+
Warnf("Interrupted, but the download is not resumable. Exiting silently.\n")
157146
}
158147
} else {
159148
err := JoinFile(files, filepath.Base(url))
@@ -168,8 +157,15 @@ func Execute(url string, state *State, conn int, skiptls bool, proxy string, bwL
168157

169158
func usage() {
170159
Printf(`Usage:
171-
hget [-n connection] [-skip-tls true] [-proxy proxy_address] [-file filename] URL
172-
hget tasks
173-
hget resume [TaskName]
160+
hget [options] URL
161+
hget [options] --resume=TaskName
162+
163+
Options:
164+
-n int number of connections (default number of CPUs)
165+
-skip-tls bool skip certificate verification for https (default true)
166+
-proxy string proxy address (e.g., '127.0.0.1:12345' for socks5 or 'http://proxy.com:8080')
167+
-file string file path containing URLs (one per line)
168+
-rate string bandwidth limit during download (e.g., 10kB, 10MiB)
169+
-resume string resume a stopped download by providing its task name or URL
174170
`)
175171
}

0 commit comments

Comments
 (0)