diff --git a/.gitignore b/.gitignore index e36f067..eae4ada 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -/mikuru-* +/mikuru diff --git a/Makefile b/Makefile index 2d759c8..8c7e576 100644 --- a/Makefile +++ b/Makefile @@ -1,13 +1,10 @@ -VERSION = `git describe --tags` || echo MIRAI - GO = go -GOFLAGS = -v -buildvcs=false -buildmode=exe -ldflags "-w -X `${GO} list`.Version=${VERSION}" +GOFLAGS = -v -buildvcs=false -buildmode=exe -ldflags='-w -X "`${GO} list`.Version=${VERSION}" -X "`${GO} list`.Revision=${REVISION}"' -build: mikuru-login mikuru-post +VERSION ?= `git describe --tags` +REVISION ?= `git rev-list --all | wc -l` -mikuru-login: - ${GO} build ${GOFLAGS} ./cmd/$@ -mikuru-post: - ${GO} build ${GOFLAGS} ./cmd/$@ +build: + @${GO} build ${GOFLAGS} -o mikuru ./cmd clean: - rm -f mikuru-* + @rm -f mikuru diff --git a/README.md b/README.md index cce46f0..d7cf9bc 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # Mikuru -[Yarn.social](https://yarn.social) client where each task (except for logout) is handled by a separate program. +A [yarn.social](https://yarn.social) client from the future ## Current status * [ ] Follow/Unfollow diff --git a/Taskfile.yml b/Taskfile.yml new file mode 100644 index 0000000..81273e1 --- /dev/null +++ b/Taskfile.yml @@ -0,0 +1,31 @@ +# https://taskfile.dev + +version: '3' + +env: + GO: go + +vars: + IMPORT: git.laidback.moe/shinyoukai/mikuru + DIR: ./cmd +tasks: + default: + cmds: + - task: build + build: + desc: Build the client + cmds: + - $GO build -ldflags='-s -w -X "{{.IMPORT}}.Version={{.VERSION}}" -X "{{.IMPORT}}.Revision={{.REVISION}}"' -v -o mikuru {{.DIR}} + vars: + REVISION: + sh: git rev-list --all | wc -l | tr -d ' ' + VERSION: + sh: git describe --tags + clean: + desc: Remove generated files + cmds: + - rm -f mikuru + tidy: + desc: Update go.mod + cmds: + - $GO mod tidy diff --git a/cmd/mikuru-login/main.go b/cmd/login.go similarity index 57% rename from cmd/mikuru-login/main.go rename to cmd/login.go index 8c0e71e..312662c 100644 --- a/cmd/mikuru-login/main.go +++ b/cmd/login.go @@ -2,14 +2,15 @@ package main import ( "fmt" - "log" - "os" "strings" "syscall" "golang.org/x/term" "go.yarn.social/client" "git.laidback.moe/shinyoukai/mikuru" + + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" ) var ( @@ -17,37 +18,38 @@ var ( password string ) +var loginCmd = &cobra.Command{ + Use: "login", + Short: "Authenticate against a Yarn.social pod", + Aliases: []string{"auth", "signin"}, + Args: cobra.MaximumNArgs(0), + Run: func(_ *cobra.Command, _ []string) { + cli, err := client.NewClient(client.WithURI(mikuru.Config.Host)) + if err != nil { + log.Fatal("Unable to create client", err) + } + signin(cli) + }, +} + func init() { mikuru.ConfInit() + rootCmd.AddCommand(loginCmd) } -func main() { - cli, err := client.NewClient(client.WithURI(mikuru.Config.Host)) - if err != nil { - log.Println("Unable to create client") - log.Fatal(err) - } - - fmt.Println("Welcome to Mikuru!") - fmt.Printf("%s\n", mikuru.PrintVersion()) - - signin(cli) -} func signin(cli *client.Client) { fmt.Printf("Username: ") fmt.Scanln(&username) if len(username) == 0 { - fmt.Println("No value. Bailing out") - os.Exit(1) + log.Fatal("No value. Bailing out") } fmt.Printf("Password: ") data, err := term.ReadPassword(int(syscall.Stdin)) if err != nil { - fmt.Printf("Unable to obtain password: %s\n", err) - os.Exit(1) + log.Fatal("Unable to obtain password", err) } password := string(data) @@ -55,15 +57,14 @@ func signin(cli *client.Client) { res, err := cli.Login(username, password) if err != nil { - fmt.Println("Unable to login") - os.Exit(1) + log.Fatal("Unable to login", err) } token := strings.Trim(fmt.Sprintf(res.Token), "{}") - fmt.Println("Login successful") fmt.Println("Place this token in your configuration file for later use") - fmt.Println("Do not share it with anyone, it's classified information") + fmt.Println("Do not share it with anyone, it's classified information!") + fmt.Println("") fmt.Printf("token = %v\n", token) } diff --git a/cmd/main.go b/cmd/main.go new file mode 100644 index 0000000..736ef31 --- /dev/null +++ b/cmd/main.go @@ -0,0 +1,5 @@ +package main + +func main() { + Execute() +} diff --git a/cmd/mikuru-post/main.go b/cmd/mikuru-post/main.go deleted file mode 100644 index 59a5d26..0000000 --- a/cmd/mikuru-post/main.go +++ /dev/null @@ -1,43 +0,0 @@ -package main - -import ( - "log" - - "git.laidback.moe/shinyoukai/mikuru" - "go.yarn.social/client" - "github.com/tj/go-editor" -) - -func init() { - mikuru.ConfInit() -} - -func main() { - cli, err := client.NewClient( - client.WithURI(mikuru.Config.Host), - client.WithToken(mikuru.Config.Token), - ) - if err != nil { - log.Fatal(err) - } - - write(cli) -} - -func write(cli *client.Client) { - var post string - - data, err := editor.Read() - - if err != nil { - log.Fatal("Unable to read content from editor") - } - - post = string(data) - - _, err = cli.Post(post, "") - - if err != nil { - log.Fatal("Unable to publish tweet") - } -} diff --git a/cmd/post.go b/cmd/post.go new file mode 100644 index 0000000..b8217e9 --- /dev/null +++ b/cmd/post.go @@ -0,0 +1,48 @@ +package main + +import ( + "git.laidback.moe/shinyoukai/mikuru" + "go.yarn.social/client" + "github.com/tj/go-editor" + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" +) + +var postCmd = &cobra.Command{ + Use: "post", + Aliases: []string{"tweet"}, + Short: "Publish a new post to a Yarn pod", + Run: func(_ *cobra.Command, args []string) { + cli, err := client.NewClient( + client.WithURI(mikuru.Config.Host), + client.WithToken(mikuru.Config.Token), + ) + if err != nil { + log.Fatal("Unable to create client", err) + } + write(cli) + }, +} + +func init() { + rootCmd.AddCommand(postCmd) + mikuru.ConfInit() +} + +func write(cli *client.Client) { + var post string + + data, err := editor.Read() + + if err != nil { + log.Fatal("Unable to read content from editor", err) + } + + post = string(data) + + _, err = cli.Post(post, "") + + if err != nil { + log.Fatal("Unable to publish tweet", err) + } +} diff --git a/cmd/root.go b/cmd/root.go new file mode 100644 index 0000000..51cdb1e --- /dev/null +++ b/cmd/root.go @@ -0,0 +1,20 @@ +package main + +import ( + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + "git.laidback.moe/shinyoukai/mikuru" +) + +var rootCmd = &cobra.Command{ + Use: "mikuru", + Short: "A client for Yarn.social from the future", + Version: mikuru.Version, +} + +func Execute() { + err := rootCmd.Execute() + if err != nil { + log.Fatal(err) + } +} diff --git a/go.mod b/go.mod index 369bfd3..265273d 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,8 @@ module git.laidback.moe/shinyoukai/mikuru go 1.24.0 require ( + github.com/sirupsen/logrus v1.9.3 + github.com/spf13/cobra v1.10.2 github.com/tj/go-editor v1.0.0 go.yarn.social/client v0.0.0-20250420114029-410ad71a453e golang.org/x/term v0.38.0 @@ -10,8 +12,9 @@ require ( ) require ( + github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/pkg/errors v0.8.1 // indirect - github.com/sirupsen/logrus v1.9.3 // indirect + github.com/spf13/pflag v1.0.9 // indirect github.com/stretchr/testify v1.11.1 // indirect go.yarn.social/types v0.0.0-20250420113154-c5a6df6d2f22 // indirect golang.org/x/sys v0.39.0 // indirect diff --git a/go.sum b/go.sum index bbe043a..4437dc3 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,9 @@ +github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= 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/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -11,14 +14,20 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU= +github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4= +github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY= +github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/tj/go-editor v1.0.0 h1:VduwRZWk5gxHbzRkS4buB9BIFzAf6Jc+vd2bLZpHzSw= github.com/tj/go-editor v1.0.0/go.mod h1:Jj9Ze2Rn2yj5DmMppydZqr9LbkIcCWrehzZ+7udOT+w= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= go.yarn.social/client v0.0.0-20250420114029-410ad71a453e h1:A4wok2/cSAbvWLjHhtCrW8dvv1XlgcGRj7H15150HhA= go.yarn.social/client v0.0.0-20250420114029-410ad71a453e/go.mod h1:+VjffjmcZMHIudGsZlnbPnavk0oSK6xf4olzExiojhg= go.yarn.social/types v0.0.0-20250420113154-c5a6df6d2f22 h1:M34aQ3AaRKE2t7JOLwoemJ65r0e8c1z4TwuHzogHvZE= diff --git a/mikuru.1 b/mikuru.1 index ffabccd..0edf659 100644 --- a/mikuru.1 +++ b/mikuru.1 @@ -3,15 +3,28 @@ .Os .Sh NAME .Nm mikuru -.Nd A yarn-compatible twtxt client from the future +.Nd A yarn.social client from the future .Sh SYNOPSIS .Nm +.Op Cm login +.Op Cm post .Sh DESCRIPTION -This client has every single part of its functionality -handled by a separate program. -.Sh SEE ALSO -.Xr mikuru-login 1 -.Xr mikuru-post 1 -.Xr mikuru-timeline 1 +This program was made by reverse engineering the reference client +due to lack of known API documentation for the client library it uses. +.Pp +It doesn't share any code with it, however. +.Sh USAGE +.Bl -tag -width 11n +.It login +Authenticate with a Yarn.social pod, +it will ask you for your credentials +(passwords are not echoed) +.It post +Publish a tweet to a Yarn.social pod, +it will open your text editor (usually $EDITOR), +and will fail if the variable is unset. +.El +.Sh FILES +.Pa ~/.config/mikuru.ini .Sh AUTHORS .An Shin'ya Minazuki Aq Mt shinyoukai@laidback.moe