xdcc-cli/main.go

204 lines
4.0 KiB
Go

package main
import (
"bufio"
"flag"
"fmt"
"os"
"strconv"
"strings"
"sync"
)
var registry *XdccProviderRegistry = nil
func init() {
registry = NewProviderRegistry()
registry.AddProvider(&XdccEuProvider{})
}
var defaultColWidths []int = []int{100, 10, -1}
const (
KiloByte = 1024
MegaByte = KiloByte * 1024
GigaByte = MegaByte * 1024
)
func FloatToString(value float64) string {
if value-float64(int64(value)) > 0 {
return strconv.FormatFloat(value, 'f', 2, 32)
}
return strconv.FormatFloat(value, 'f', 0, 32)
}
func formatSize(size int64) string {
if size < 0 {
return "--"
}
if size >= GigaByte {
return FloatToString(float64(size)/float64(GigaByte)) + "GB"
} else if size >= MegaByte {
return FloatToString(float64(size)/float64(MegaByte)) + "MB"
} else if size >= KiloByte {
return FloatToString(float64(size)/float64(KiloByte)) + "KB"
}
return FloatToString(float64(size)) + "B"
}
func searchCommand(args []string) {
searchCmd := flag.NewFlagSet("search", flag.ExitOnError)
sortByFilename := searchCmd.Bool("s", false, "sort results by filename")
args = parseFlags(searchCmd, args)
printer := NewTablePrinter([]string{"File Name", "Size", "URL"})
printer.SetMaxWidths(defaultColWidths)
if len(args) < 1 {
fmt.Println("search: no keyword provided.")
os.Exit(1)
}
res, _ := registry.Search(args[0])
for _, fileInfo := range res {
printer.AddRow(Row{fileInfo.Name, formatSize(fileInfo.Size), fileInfo.Url})
}
if *sortByFilename {
printer.SortByColumn(0)
}
printer.Print()
}
func transferLoop(transfer *XdccTransfer) {
pb := NewProgressBar()
evts := transfer.PollEvents()
quit := false
for !quit {
e := <-evts
switch evtType := e.(type) {
case *TransferStartedEvent:
pb.SetTotal(int(evtType.FileSize))
pb.SetFileName(evtType.FileName)
pb.SetState(ProgressStateDownloading)
case *TransferProgessEvent:
pb.Increment(int(evtType.transferBytes))
case *TransferCompletedEvent:
pb.SetState(ProgressStateCompleted)
quit = true
}
}
// TODO: do clean-up operations here
}
func doTransfer(transfer *XdccTransfer) {
err := transfer.Start()
if err != nil {
fmt.Println(err)
return
}
transferLoop(transfer)
}
func parseFlags(flagSet *flag.FlagSet, args []string) []string {
findFirstFlag := func(args []string) int {
for i, arg := range args {
if strings.HasPrefix(arg, "-") || strings.HasPrefix(arg, "--") {
return i
}
}
return -1
}
flagIdx := findFirstFlag(args)
if flagIdx >= 0 {
flagSet.Parse(args[flagIdx:])
return args[:flagIdx]
}
return args
}
func loadUrlListFile(filePath string) []string {
file, err := os.Open(filePath)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
urlList := make([]string, 0)
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
urlList = append(urlList, line)
}
if err := scanner.Err(); err != nil {
fmt.Println(err)
os.Exit(1)
}
return urlList
}
func getCommand(args []string) {
getCmd := flag.NewFlagSet("get", flag.ExitOnError)
path := getCmd.String("o", ".", "output folder of dowloaded file")
inputFile := getCmd.String("i", "", "input file containing a list of urls")
urlList := parseFlags(getCmd, args)
if *inputFile != "" {
urlList = append(urlList, loadUrlListFile(*inputFile)...)
}
if len(urlList) == 0 {
fmt.Println("no file url provided")
os.Exit(1)
}
wg := sync.WaitGroup{}
for _, urlStr := range urlList {
if strings.HasPrefix(urlStr, "irc://") {
url, err := parseIRCFileURl(urlStr)
if err != nil {
fmt.Println(err.Error())
os.Exit(1)
}
wg.Add(1)
transfer := NewXdccTransfer(*url, *path)
go func(transfer *XdccTransfer) {
doTransfer(transfer)
wg.Done()
}(transfer)
} else {
}
}
wg.Wait()
}
func main() {
if len(os.Args) < 2 {
fmt.Println("one of the following subcommands is expected: [search, get]")
os.Exit(1)
}
switch os.Args[1] {
case "search":
searchCommand(os.Args[2:])
case "get":
getCommand(os.Args[2:])
default:
fmt.Println("no such command: ", os.Args[1])
os.Exit(1)
}
}