diff --git a/README.md b/README.md index 87f773e..8438a31 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ You can also use apps like `ffplay` or `vlc`: * `opencv` - use `OpenCV` library to access camera ([gocv](https://github.com/hybridgroup/gocv)) * `libjpeg` - build with `libjpeg` ([go-libjpeg](https://github.com/pixiv/go-libjpeg)) instead of native Go `image/jpeg` -* `jpegli` - build with `jpegli` ([go-libjpeg](https://github.com/gen2brain/jpegli)) instead of native Go `image/jpeg` +* `jpegli` - build with `jpegli` ([jpegli](https://github.com/gen2brain/jpegli)) instead of native Go `image/jpeg` ### Download @@ -42,25 +42,25 @@ This command will install `cam2ip` in `GOBIN`, you can point `GOBIN` to e.g. `/u ### Usage ``` -Usage of cam2ip: - -bind-addr string - Bind address [CAM2IP_BIND_ADDR] (default ":56000") - -delay int - Delay between frames, in milliseconds [CAM2IP_DELAY] (default 10) - -height float - Frame height [CAM2IP_HEIGHT] (default 480) - -htpasswd-file string - Path to htpasswd file, if empty auth is disabled [CAM2IP_HTPASSWD_FILE] - -index int - Camera index [CAM2IP_INDEX] - -nowebgl - Disable WebGL drawing of images (html handler) [CAM2IP_NOWEBGL] - -rotate int - Rotate image, valid values are 90, 180, 270 [CAM2IP_ROTATE] - -timestamp - Draws timestamp on images [CAM2IP_TIMESTAMP] - -width float - Frame width [CAM2IP_WIDTH] (default 640) +Usage: cam2ip [] + --index + Camera index [CAM2IP_INDEX] (default "0") + --delay + Delay between frames, in milliseconds [CAM2IP_DELAY] (default "10") + --width + Frame width [CAM2IP_WIDTH] (default "640") + --height + Frame height [CAM2IP_HEIGHT] (default "480") + --rotate + Rotate image, valid values are 90, 180, 270 [CAM2IP_ROTATE] (default "0") + --no-webgl + Disable WebGL drawing of images (html handler) [CAM2IP_NO_WEBGL] (default "false") + --timestamp + Draws timestamp on images [CAM2IP_TIMESTAMP] (default "false") + --bind-addr + Bind address [CAM2IP_BIND_ADDR] (default ":56000") + --htpasswd-file + Path to htpasswd file, if empty auth is disabled [CAM2IP_HTPASSWD_FILE] (default "") ``` ### Handlers diff --git a/cmd/cam2ip/main.go b/cmd/cam2ip/main.go index 57b5977..985cd24 100644 --- a/cmd/cam2ip/main.go +++ b/cmd/cam2ip/main.go @@ -5,7 +5,7 @@ import ( "fmt" "os" - "github.com/jamiealquiza/envy" + "go.senan.xyz/flagconf" "github.com/gen2brain/cam2ip/camera" "github.com/gen2brain/cam2ip/server" @@ -19,41 +19,50 @@ const ( func main() { srv := server.NewServer() - flag.IntVar(&srv.Index, "index", 0, "Camera index") - flag.IntVar(&srv.Delay, "delay", 10, "Delay between frames, in milliseconds") - flag.Float64Var(&srv.FrameWidth, "width", 640, "Frame width") - flag.Float64Var(&srv.FrameHeight, "height", 480, "Frame height") - flag.IntVar(&srv.Rotate, "rotate", 0, "Rotate image, valid values are 90, 180, 270") - flag.BoolVar(&srv.NoWebGL, "nowebgl", false, "Disable WebGL drawing of images (html handler)") - flag.BoolVar(&srv.Timestamp, "timestamp", false, "Draws timestamp on images") - flag.StringVar(&srv.Bind, "bind-addr", ":56000", "Bind address") - flag.StringVar(&srv.Htpasswd, "htpasswd-file", "", "Path to htpasswd file, if empty auth is disabled") + flag.IntVar(&srv.Index, "index", 0, "Camera index [CAM2IP_INDEX]") + flag.IntVar(&srv.Delay, "delay", 10, "Delay between frames, in milliseconds [CAM2IP_DELAY]") + flag.Float64Var(&srv.FrameWidth, "width", 640, "Frame width [CAM2IP_WIDTH]") + flag.Float64Var(&srv.FrameHeight, "height", 480, "Frame height [CAM2IP_HEIGHT]") + flag.IntVar(&srv.Rotate, "rotate", 0, "Rotate image, valid values are 90, 180, 270 [CAM2IP_ROTATE]") + flag.BoolVar(&srv.NoWebGL, "no-webgl", false, "Disable WebGL drawing of images (html handler) [CAM2IP_NO_WEBGL]") + flag.BoolVar(&srv.Timestamp, "timestamp", false, "Draws timestamp on images [CAM2IP_TIMESTAMP]") + flag.StringVar(&srv.Bind, "bind-addr", ":56000", "Bind address [CAM2IP_BIND_ADDR]") + flag.StringVar(&srv.Htpasswd, "htpasswd-file", "", "Path to htpasswd file, if empty auth is disabled [CAM2IP_HTPASSWD_FILE]") + + flag.Usage = func() { + stderr("Usage: %s []\n", name) + order := []string{"index", "delay", "width", "height", "rotate", "no-webgl", "timestamp", "bind-addr", "htpasswd-file"} + + for _, name := range order { + f := flag.Lookup(name) + if f != nil { + stderr(" --%s\n \t%v (default %q)\n", f.Name, f.Usage, f.DefValue) + } + } + } - envy.Parse("CAM2IP") flag.Parse() + _ = flagconf.ParseEnv() srv.Name = name srv.Version = version - var err error - if srv.Htpasswd != "" { - if _, err = os.Stat(srv.Htpasswd); err != nil { - fmt.Fprintf(os.Stderr, "%s\n", err.Error()) + if _, err := os.Stat(srv.Htpasswd); err != nil { + stderr("%s\n", err.Error()) os.Exit(1) } } - if srv.FileName != "" { - if _, err = os.Stat(srv.FileName); err != nil { - fmt.Fprintf(os.Stderr, "%s\n", err.Error()) - os.Exit(1) - } - } - - cam, err := camera.New(camera.Options{srv.Index, srv.Rotate, srv.FrameWidth, srv.FrameHeight, srv.Timestamp}) + cam, err := camera.New(camera.Options{ + Index: srv.Index, + Rotate: srv.Rotate, + Width: srv.FrameWidth, + Height: srv.FrameHeight, + Timestamp: srv.Timestamp, + }) if err != nil { - fmt.Fprintf(os.Stderr, "%s\n", err.Error()) + stderr("%s\n", err.Error()) os.Exit(1) } @@ -61,11 +70,15 @@ func main() { defer srv.Reader.Close() - fmt.Fprintf(os.Stderr, "Listening on %s\n", srv.Bind) + stderr("Listening on %s\n", srv.Bind) err = srv.ListenAndServe() if err != nil { - fmt.Fprintf(os.Stderr, "%s\n", err.Error()) + stderr("%s\n", err.Error()) os.Exit(1) } } + +func stderr(format string, a ...any) { + _, _ = fmt.Fprintf(os.Stderr, format, a...) +} diff --git a/go.mod b/go.mod index d4bffd4..cbde9db 100644 --- a/go.mod +++ b/go.mod @@ -6,21 +6,18 @@ require ( github.com/coder/websocket v1.8.13 github.com/gen2brain/base64 v0.0.0-20221015184129-317a5c93030c github.com/gen2brain/jpegli v0.3.4 - github.com/jamiealquiza/envy v1.1.0 github.com/korandiz/v4l v1.1.0 github.com/pbnjay/pixfont v0.0.0-20200714042608-33b744692567 github.com/pixiv/go-libjpeg v0.0.0-20190822045933-3da21a74767d + go.senan.xyz/flagconf v0.1.9 gocv.io/x/gocv v0.35.0 ) require ( - github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/spf13/cobra v1.8.0 // indirect - github.com/spf13/pflag v1.0.5 // indirect github.com/tetratelabs/wazero v1.9.0 // indirect golang.org/x/crypto v0.18.0 // indirect golang.org/x/net v0.20.0 // indirect - golang.org/x/sys v0.16.0 // indirect + golang.org/x/sys v0.19.0 // indirect ) go 1.23 diff --git a/go.sum b/go.sum index ec04eb9..9b11999 100644 --- a/go.sum +++ b/go.sum @@ -4,16 +4,11 @@ github.com/anthonynsimon/bild v0.14.0 h1:IFRkmKdNdqmexXHfEU7rPlAmdUZ8BDZEGtGHDnG github.com/anthonynsimon/bild v0.14.0/go.mod h1:hcvEAyBjTW69qkKJTfpcDQ83sSZHxwOunsseDfeQhUs= github.com/coder/websocket v1.8.13 h1:f3QZdXy7uGVz+4uCJy2nTZyM0yTBj8yANEHhqlXZ9FE= github.com/coder/websocket v1.8.13/go.mod h1:LNVeNrXQZfe5qhS9ALED3uA+l5pPqvwXg3CKoDBB2gs= -github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/gen2brain/base64 v0.0.0-20221015184129-317a5c93030c h1:TUjjeJ2rV4KZxH6hIEi/boEQB3v6aKvwdakUJR3AwiE= github.com/gen2brain/base64 v0.0.0-20221015184129-317a5c93030c/go.mod h1:VG58IUyxPWojCtGwqwoZ/6LLXwClu1tssqa5ktOxI9o= github.com/gen2brain/jpegli v0.3.4 h1:wFoUHIjfPJGGeuW3r9dqy0MTT1TtvJuWf6EqfHPPGFM= github.com/gen2brain/jpegli v0.3.4/go.mod h1:tVnF7NPyufTo8noFlW5lurUUwZW8trwBENOItzuk2BM= github.com/hybridgroup/mjpeg v0.0.0-20140228234708-4680f319790e/go.mod h1:eagM805MRKrioHYuU7iKLUyFPVKqVV6um5DAvCkUtXs= -github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= -github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/jamiealquiza/envy v1.1.0 h1:Nwh4wqTZ28gDA8zB+wFkhnUpz3CEcO12zotjeqqRoKE= -github.com/jamiealquiza/envy v1.1.0/go.mod h1:MP36BriGCLwEHhi1OU8E9569JNZrjWfCvzG7RsPnHus= github.com/korandiz/v4l v1.1.0 h1:VbzaWlhqNzVPfHEYEM+V8T7184ndiEzljJgDHSHc7pc= github.com/korandiz/v4l v1.1.0/go.mod h1:pftxPG7hkuUgepioAY6PAE81mShaVjzd95X/WF4Izus= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= @@ -21,20 +16,19 @@ github.com/pbnjay/pixfont v0.0.0-20200714042608-33b744692567 h1:pKjmNHL7BCXhgsnS github.com/pbnjay/pixfont v0.0.0-20200714042608-33b744692567/go.mod h1:ytYavTmrpWG4s7UOfDhP6m4ASL5XA66nrOcUn1e2M78= github.com/pixiv/go-libjpeg v0.0.0-20190822045933-3da21a74767d h1:ls+7AYarUlUSetfnN/DKVNcK6W8mQWc6VblmOm4XwX0= github.com/pixiv/go-libjpeg v0.0.0-20190822045933-3da21a74767d/go.mod h1:DO7ixpslN6XfbWzeNH9vkS5CF2FQUX81B85rYe9zDxU= -github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= -github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/tetratelabs/wazero v1.9.0 h1:IcZ56OuxrtaEz8UYNRHBrUa9bYeX9oVY93KspZZBf/I= github.com/tetratelabs/wazero v1.9.0/go.mod h1:TSbcXCfFP0L2FGkRPxHphadXPjo1T6W+CseNNY7EkjM= +go.senan.xyz/flagconf v0.1.9 h1:LBDmqiVFgijfqFXDzH97gPn0qDbg1Dq6/vxsxS/TzC4= +go.senan.xyz/flagconf v0.1.9/go.mod h1:NqOFfSwJvNWXOTUabcRZ8mPK9+sJmhStJhqtEt74wNQ= gocv.io/x/gocv v0.35.0 h1:Qaxb5KdVyy8Spl4S4K0SMZ6CVmKtbfoSGQAxRD3FZlw= gocv.io/x/gocv v0.35.0/go.mod h1:oc6FvfYqfBp99p+yOEzs9tbYF9gOrAQSeL/dyIPefJU= golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= -golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= -golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= +golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY= +golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg=