mirror of
https://github.com/GopeedLab/gopeed.git
synced 2026-11-06 16:40:32 +00:00
feat: cli
This commit is contained in:
1 parent
caf9bf265b
commit
359f28bb1f
12 files changed
+209
-97
No files matched your search
Vendored
-17
@@ -1,17 +0,0 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Launch",
|
||||
"type": "go",
|
||||
"request": "launch",
|
||||
"mode": "auto",
|
||||
"program": "${fileDirname}",
|
||||
"env": {},
|
||||
"args": []
|
||||
}
|
||||
]
|
||||
}
|
||||
Vendored
-9
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"go.useLanguageServer": true,
|
||||
"[go]": {
|
||||
"editor.formatOnSave": true,
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.organizeImports": true
|
||||
}
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
type args struct {
|
||||
url string
|
||||
connections *int
|
||||
dir *string
|
||||
}
|
||||
|
||||
func parse() *args {
|
||||
dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
var args args
|
||||
args.connections = flag.Int("C", 16, "Concurrent connections.")
|
||||
args.dir = flag.String("D", dir, "Save directory.")
|
||||
flag.Parse()
|
||||
t := flag.Args()
|
||||
if len(t) > 0 {
|
||||
args.url = t[0]
|
||||
} else {
|
||||
gPrintln("missing url parameter")
|
||||
gPrintln("try 'gopeed -h' for more information")
|
||||
os.Exit(1)
|
||||
}
|
||||
return &args
|
||||
}
|
||||
|
||||
func gPrint(msg string) {
|
||||
fmt.Print("gopeed: " + msg)
|
||||
}
|
||||
|
||||
func gPrintln(msg string) {
|
||||
gPrint(msg + "\n")
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/monkeyWie/gopeed-core/download"
|
||||
"github.com/monkeyWie/gopeed-core/download/base"
|
||||
"github.com/monkeyWie/gopeed-core/download/http"
|
||||
"github.com/monkeyWie/gopeed-core/util"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
)
|
||||
|
||||
const progressWidth = 20
|
||||
|
||||
func main() {
|
||||
args := parse()
|
||||
|
||||
downloader := download.NewDownloader(http.FetcherBuilder)
|
||||
res, err := downloader.Resolve(&base.Request{
|
||||
URL: args.url,
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = downloader.Create(res, &base.Options{
|
||||
Path: *args.dir,
|
||||
Connections: *args.connections,
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
downloader.Listener(func(taskInfo *download.TaskInfo, eventKey base.EventKey) {
|
||||
if eventKey == base.EventKeyProgress {
|
||||
printProgress(taskInfo, "downloading...")
|
||||
}
|
||||
if eventKey == base.EventKeyDone {
|
||||
printProgress(taskInfo, "complete")
|
||||
wg.Done()
|
||||
}
|
||||
})
|
||||
wg.Wait()
|
||||
fmt.Println()
|
||||
gPrint("saving file " + filepath.Join(*args.dir, res.Files[0].Name))
|
||||
}
|
||||
|
||||
func printProgress(taskInfo *download.TaskInfo, title string) {
|
||||
rate := float64(taskInfo.Progress.Downloaded) / float64(taskInfo.Res.TotalSize)
|
||||
completeWidth := int(progressWidth * rate)
|
||||
speed := util.ByteFmt(taskInfo.Progress.Speed)
|
||||
totalSize := util.ByteFmt(taskInfo.Res.TotalSize)
|
||||
fmt.Printf("\r%s [", title)
|
||||
for i := 0; i < progressWidth; i++ {
|
||||
if i < completeWidth {
|
||||
fmt.Print("■")
|
||||
} else {
|
||||
fmt.Print("□")
|
||||
}
|
||||
}
|
||||
fmt.Printf("] %.1f%% %s/s %s", rate*100, speed, totalSize)
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/monkeyWie/gopeed-core/download"
|
||||
"github.com/monkeyWie/gopeed-core/download/base"
|
||||
"github.com/monkeyWie/gopeed-core/download/http"
|
||||
"github.com/superhawk610/bar"
|
||||
"github.com/ttacon/chalk"
|
||||
"strconv"
|
||||
"sync"
|
||||
)
|
||||
|
||||
func main() {
|
||||
b := bar.NewWithOpts(
|
||||
bar.WithDimensions(10000, 20),
|
||||
bar.WithDisplay("[", "■", "■", "□", "]"),
|
||||
bar.WithFormat(
|
||||
fmt.Sprintf(
|
||||
" %s:status%s :percent :bar%s :speedKB/s%s ",
|
||||
chalk.Green,
|
||||
chalk.Reset,
|
||||
chalk.Blue,
|
||||
chalk.Reset,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
downloader := download.NewDownloader(http.FetcherBuilder)
|
||||
res, err := downloader.Resolve(&base.Request{
|
||||
URL: "https://dldir1.qq.com/weixin/Windows/WeChatSetup.exe",
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = downloader.Create(res, &base.Options{
|
||||
Path: "E:\\test\\gopeed\\http",
|
||||
Connections: 4,
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
downloader.Listener(func(taskInfo *download.TaskInfo, eventKey base.EventKey) {
|
||||
if eventKey == base.EventKeyProgress {
|
||||
b.Update(int(10000*(float64(taskInfo.Progress.Downloaded)/float64(taskInfo.Res.TotalSize))), bar.Context{
|
||||
bar.Ctx("status", "downloading..."),
|
||||
bar.Ctx("speed", strconv.Itoa(int(taskInfo.Progress.Speed/1024))),
|
||||
})
|
||||
}
|
||||
if eventKey == base.EventKeyDone {
|
||||
b.Update(10000, bar.Context{
|
||||
bar.Ctx("status", "complete"),
|
||||
bar.Ctx("speed", strconv.Itoa(int(taskInfo.Progress.Speed/1024))),
|
||||
})
|
||||
wg.Done()
|
||||
}
|
||||
})
|
||||
wg.Wait()
|
||||
b.Done()
|
||||
}
|
||||
@@ -17,6 +17,7 @@ type EventKey string
|
||||
const (
|
||||
EventKeyStart = "start"
|
||||
EventKeyPause = "pause"
|
||||
EventKeyContinue = "continue"
|
||||
EventKeyProgress = "progress"
|
||||
EventKeyError = "error"
|
||||
EventKeyDone = "done"
|
||||
|
||||
@@ -121,7 +121,14 @@ func (d *Downloader) Create(res *base.Resource, opts *base.Options) (err error)
|
||||
d.emit(task, base.EventKeyError)
|
||||
} else {
|
||||
task.Progress.Used = task.timer.Used()
|
||||
task.Progress.Speed = task.Res.TotalSize / (task.Progress.Used / int64(time.Second))
|
||||
if task.Res.TotalSize == 0 {
|
||||
task.Res.TotalSize = task.fetcher.Progress().TotalDownloaded()
|
||||
}
|
||||
used := task.Progress.Used / int64(time.Second)
|
||||
if used == 0 {
|
||||
used = 1
|
||||
}
|
||||
task.Progress.Speed = task.Res.TotalSize / used
|
||||
task.Progress.Downloaded = task.Res.TotalSize
|
||||
d.emit(d.tasks[id], base.EventKeyDone)
|
||||
}
|
||||
@@ -144,7 +151,7 @@ func (d *Downloader) Continue(id string) {
|
||||
defer task.locker.Unlock()
|
||||
task.timer.Continue()
|
||||
task.fetcher.Continue()
|
||||
d.emit(task, base.EventKeyStart)
|
||||
d.emit(task, base.EventKeyContinue)
|
||||
}
|
||||
|
||||
func (d *Downloader) Listener(fn func(taskInfo *TaskInfo, eventKey base.EventKey)) {
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -117,8 +118,8 @@ func (f *Fetcher) Resolve(req *base.Request) (*base.Resource, error) {
|
||||
}
|
||||
}
|
||||
// Get file filename by URL
|
||||
if file.Name == "" {
|
||||
file.Name = path.Base(req.URL)
|
||||
if file.Name == "" && strings.Count(req.URL, "/") > 2 {
|
||||
file.Name = filepath.Base(req.URL)
|
||||
}
|
||||
// unknown file filename
|
||||
if file.Name == "" {
|
||||
|
||||
@@ -5,13 +5,13 @@ go 1.13
|
||||
require (
|
||||
github.com/RoaringBitmap/roaring v0.4.21
|
||||
github.com/cenkalti/mse v0.0.0-20140930130441-6ef65f170972
|
||||
github.com/gizak/termui/v3 v3.1.0
|
||||
github.com/google/uuid v1.1.1
|
||||
github.com/marksamman/bencode v0.0.0-20150821143521-dc84f26e086e
|
||||
github.com/mattn/go-tty v0.0.3 // indirect
|
||||
github.com/sirupsen/logrus v1.4.2
|
||||
github.com/superhawk610/bar v0.0.2
|
||||
github.com/superhawk610/terminal v0.1.0 // indirect
|
||||
github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
||||
)
|
||||
@@ -6,6 +6,8 @@ github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8
|
||||
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/gizak/termui/v3 v3.1.0 h1:ZZmVDgwHl7gR7elfKf1xc4IudXZ5qqfDh4wExk4Iajc=
|
||||
github.com/gizak/termui/v3 v3.1.0/go.mod h1:bXQEBkJpzxUAKf0+xq9MSWAvWZlE7c+aidmyFlkYTrY=
|
||||
github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2 h1:Ujru1hufTHVb++eG6OuNDKMxZnGIvF6o/u8q/8h2+I4=
|
||||
github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
|
||||
github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31 h1:gclg6gY70GLy3PbkQ1AERPfmLMMagS60DKF78eWwLn8=
|
||||
@@ -26,11 +28,17 @@ github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVc
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10=
|
||||
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
||||
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mattn/go-runewidth v0.0.6 h1:V2iyH+aX9C5fsYCpK60U8BYIvmhqxuOL3JZcqc1NB7k=
|
||||
github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-tty v0.0.3 h1:5OfyWorkyO7xP52Mq7tB36ajHDG5OHrmBGIS/DtakQI=
|
||||
github.com/mattn/go-tty v0.0.3/go.mod h1:ihxohKRERHTVzN+aSVRwACLCeqIoZAWpoICkkvrWyR0=
|
||||
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 h1:DpOJ2HYzCv8LZP15IdmG+YdwD2luVPHITV96TkirNBM=
|
||||
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
|
||||
github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae h1:VeRdUYdCw49yizlSbMEn2SZ+gT+3IUKx8BqxyQdz+BY=
|
||||
github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg=
|
||||
github.com/nsf/termbox-go v0.0.0-20190121233118-02980233997d h1:x3S6kxmy49zXVVyhcnrFqxvNVCBPb2KZ9hV2RBdS840=
|
||||
github.com/nsf/termbox-go v0.0.0-20190121233118-02980233997d/go.mod h1:IuKpRQcYE1Tfu+oAQqaLisqDeXgjyyltCfsaoYN18NQ=
|
||||
github.com/philhofer/fwd v1.0.0 h1:UbZqGr5Y38ApvM/V/jEljVxwocdweyH+vmYvRPBnbqQ=
|
||||
github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
@@ -48,11 +56,10 @@ github.com/superhawk610/terminal v0.1.0 h1:OpWp0+861M3l5j4ZWprm8q0fgG9Y2xXZp5tku
|
||||
github.com/superhawk610/terminal v0.1.0/go.mod h1:NQ3EEKWSeofexUwENLX3lv4WR2qeGiLlbf/NveZ7ZAQ=
|
||||
github.com/tinylib/msgp v1.1.0 h1:9fQd+ICuRIu/ue4vxJZu6/LzxN0HwMds2nq/0cFvxHU=
|
||||
github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
||||
github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31 h1:OXcKh35JaYsGMRzpvFkLv/MEyPuL49CThT1pZ8aSml4=
|
||||
github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31/go.mod h1:onvgF043R+lC5RZ8IT9rBXDaEDnpnw/Cl+HFiw+v/7Q=
|
||||
github.com/willf/bitset v1.1.10 h1:NotGKqX0KwQ72NUzqrjZq5ipPNDQex9lo3WpaS8L2sc=
|
||||
github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU=
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
)
|
||||
|
||||
var unitArr = []string{"B", "KB", "MB", "GB", "TB", "EB"}
|
||||
|
||||
func ByteFmt(size int64) string {
|
||||
if size == 0 {
|
||||
return "unknown"
|
||||
}
|
||||
fs := float64(size)
|
||||
p := int(math.Log(fs) / math.Log(1024))
|
||||
val := fs / math.Pow(1024, float64(p))
|
||||
_, frac := math.Modf(val)
|
||||
if frac > 0 {
|
||||
return fmt.Sprintf("%.1f%s", math.Floor(val*10)/10, unitArr[p])
|
||||
} else {
|
||||
return fmt.Sprintf("%d%s", int(val), unitArr[p])
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package util
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestByteFmt(t *testing.T) {
|
||||
type args struct {
|
||||
size int64
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "100B",
|
||||
args: args{size: int64(100)},
|
||||
want: "100B",
|
||||
},
|
||||
{
|
||||
name: "1KB",
|
||||
args: args{size: int64(1024)},
|
||||
want: "1KB",
|
||||
},
|
||||
{
|
||||
name: "1.9KB",
|
||||
args: args{size: int64(1024*2 - 1)},
|
||||
want: "1.9KB",
|
||||
},
|
||||
{
|
||||
name: "2KB",
|
||||
args: args{size: int64(1024 * 2)},
|
||||
want: "2KB",
|
||||
},
|
||||
{
|
||||
name: "1MB",
|
||||
args: args{size: int64(1024 * 1024)},
|
||||
want: "1MB",
|
||||
},
|
||||
{
|
||||
name: "1.9MB",
|
||||
args: args{size: int64(1024*1024*2 - 1)},
|
||||
want: "1.9MB",
|
||||
},
|
||||
{
|
||||
name: "2MB",
|
||||
args: args{size: int64(1024 * 1024 * 2)},
|
||||
want: "2MB",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := ByteFmt(tt.args.size); got != tt.want {
|
||||
t.Errorf("ByteFmt() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user