From ca4aff040e249a3f2e8f0fded922bbd2a54c8943 Mon Sep 17 00:00:00 2001 From: Simon Vieille Date: Mon, 22 Aug 2022 15:42:45 +0200 Subject: [PATCH] add play/download commands --- main.go | 212 ++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 200 insertions(+), 12 deletions(-) diff --git a/main.go b/main.go index fbeed02..48ecffe 100644 --- a/main.go +++ b/main.go @@ -5,11 +5,18 @@ import ( "net/http" "os" "path/filepath" + "strconv" + "bufio" + "encoding/json" "github.com/h2non/filetype" "github.com/labstack/echo/v4" "github.com/labstack/echo/v4/middleware" "github.com/urfave/cli/v2" + "io/ioutil" + netUrl "net/url" + "os/exec" + "regexp" "strings" ) @@ -19,15 +26,10 @@ var version = "dev" func main() { app := &cli.App{ - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "debug", - }, - }, Commands: []*cli.Command{ { Name: "serve", - Aliases: []string{"c"}, + Aliases: []string{"s"}, Flags: []cli.Flag{ &cli.StringFlag{ Name: "listen", @@ -49,8 +51,11 @@ func main() { Aliases: []string{"d"}, Value: ".", }, + &cli.StringFlag{ + Name: "debug", + }, }, - Usage: "complete a task on the list", + Usage: "run http server to serve api and files", Action: func(ctx *cli.Context) error { listen := ctx.String("listen") port := ctx.Int64("port") @@ -77,6 +82,36 @@ func main() { return nil }, }, + { + Name: "play", + Aliases: []string{"p"}, + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "api-url", + Aliases: []string{"u"}, + Value: "http://127.0.0.1:4000", + }, + }, + Usage: "run client", + Action: func(ctx *cli.Context) error { + return runShell(ctx, "play") + }, + }, + { + Name: "download", + Aliases: []string{"d"}, + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "api-url", + Aliases: []string{"u"}, + Value: "http://127.0.0.1:4000", + }, + }, + Usage: "run client", + Action: func(ctx *cli.Context) error { + return runShell(ctx, "download") + }, + }, }, } @@ -137,7 +172,7 @@ func getFiles(directory, url string) ([]File, error) { Name: basename, Path: path, RelativePath: relativePath, - Url: fmt.Sprintf("%s/api/stream?path=%s", url, relativePath), + Url: fmt.Sprintf("%s/api/stream?path=%s", url, netUrl.QueryEscape(relativePath)), } file.GenerateHeadAndContentType() @@ -164,16 +199,15 @@ func apiStream(e echo.Context, directory, url string) error { return e.JSON(http.StatusInternalServerError, ApiError{Error: fmt.Sprintf("%s", err)}) } - fmt.Printf("%+v\n", path) - if path == "" { return e.JSON(http.StatusBadRequest, ApiError{Error: "\"path\" query param is missing"}) } for _, file := range files { if file.RelativePath == path { - stat, _ := os.Stat(file.Path) - e.Response().Header().Add("Content-Length", string(stat.Size())) + // stat, _ := os.Stat(file.Path) + e.Response().Header().Del("Content-Length") + //e.Response().Header().Set("Content-Length", string(stat.Size())) http.ServeFile(e.Response(), e.Request(), file.Path) } } @@ -190,3 +224,157 @@ func apiList(e echo.Context, directory, url string) error { return e.JSONPretty(http.StatusOK, files, " ") } + +func runShell(ctx *cli.Context, action string) error { + url := strings.TrimSuffix(ctx.String("api-url"), "/") + response, err := http.Get(fmt.Sprintf("%s/api/list", url)) + + if err != nil { + fmt.Println(err) + + return nil + } + + body, err := ioutil.ReadAll(response.Body) + + var files []File + + json.Unmarshal([]byte(body), &files) + + size := len(files) + + for key, file := range files { + fmt.Printf("[%3d] %s\n", size-key, file.Name) + } + + reader := bufio.NewReader(os.Stdin) + + fmt.Print("> [1] ") + input, _ := reader.ReadString('\n') + input = strings.Replace(input, "\n", "", -1) + + if input == "" { + input = "1" + } + + if input == "q" { + return nil + } + + range1Regex := "^([0-9]+)-([0-9]+)$" + range2Regex := "^([0-9]+)-$" + range3Regex := "^([0-9]+)\\+$" + + isRange1, _ := regexp.MatchString(range1Regex, input) + isRange2, _ := regexp.MatchString(range2Regex, input) + isRange3, _ := regexp.MatchString(range3Regex, input) + + var result []File + + if input == "*" || input == "*+" { + for i := len(files) - 1; i >= 0; i-- { + result = append(result, files[i]) + } + } else if input == "-*" { + result = files + } else if isRange1 { // a-b + regex, _ := regexp.Compile(range1Regex) + data := regex.FindStringSubmatch(input) + + a, _ := strconv.Atoi(data[1]) + b, _ := strconv.Atoi(data[2]) + + if a > b { + for i := a - 1; i >= b-1; i-- { + result = append(result, files[i]) + fmt.Println(i) + } + } else { + for i := b - 1; i >= a-1; i-- { + result = append(result, files[i]) + fmt.Println(i) + } + } + } else if isRange2 { // a- + regex, _ := regexp.Compile(range2Regex) + data := regex.FindStringSubmatch(input) + + a, _ := strconv.Atoi(data[1]) + + for i := a - 1; i >= 0; i-- { + result = append(result, files[i]) + fmt.Println(i) + } + } else if isRange3 { // a+ + regex, _ := regexp.Compile(range3Regex) + data := regex.FindStringSubmatch(input) + + a, _ := strconv.Atoi(data[1]) + + for i := a - 1; i < len(files); i++ { + result = append(result, files[i]) + fmt.Println(i) + } + } else { + words := strings.Fields(input) + + for _, word := range words { + isInt, _ := regexp.MatchString("^[0-9]+$", word) + + if isInt { + value, _ := strconv.Atoi(word) + result = append(result, files[value-1]) + } + } + } + + if len(result) == 0 { + fmt.Println("Empty list") + + return nil + } + + var cmds []*exec.Cmd + + if action == "play" { + cmd := exec.Command("mpv", "-fs") + + for _, f := range result { + cmd.Args = append(cmd.Args, f.Url) + } + + cmds = append(cmds, cmd) + } else { + for _, f := range result { + output := fmt.Sprintf("/home/simon/Videos/%s", f.Name) + cmd := exec.Command("wget", "-o", "/dev/stdout", "-c", "--show-progress", "-O", output, f.Url) + cmds = append(cmds, cmd) + } + } + + for _, cmd := range cmds { + stdout, _ := cmd.StdoutPipe() + scanner := bufio.NewScanner(stdout) + + cmd.Start() + + for scanner.Scan() { + out := fmt.Sprintf("%q", scanner.Text()) + out = strings.Trim(out, "\"") + out = strings.ReplaceAll(out, `\u00a0`, " ") + + if out != "" { + fmt.Print("\r") + fmt.Print(out) + } else { + fmt.Print("\n") + } + } + } + + for _, cmd := range cmds { + cmd.Wait() + } + + return nil +}