5 Commits

Author SHA1 Message Date
60e17ecc4b Make the line shorter
Signed-off-by: Shin'ya Minazuki <shinyoukai@laidback.moe>
2026-01-03 17:27:12 -03:00
375c3e9cb5 Hm
Signed-off-by: Shin'ya Minazuki <shinyoukai@laidback.moe>
2026-01-03 17:11:32 -03:00
613576f438 Reorganize the project layout, fix some logging quirks
Signed-off-by: Shin'ya Minazuki <shinyoukai@laidback.moe>
2025-12-30 19:13:42 -03:00
a2a93adfb6 Support follow/unfollow actions
Signed-off-by: Shin'ya Minazuki <shinyoukai@laidback.moe>
2025-12-30 14:31:48 -03:00
3b06d6b773 Yarn already implies where it comes from
Signed-off-by: Shin'ya Minazuki <shinyoukai@laidback.moe>
2025-12-30 13:53:55 -03:00
14 changed files with 142 additions and 37 deletions

View File

@@ -1,6 +1,6 @@
ISC License (ISCL) ISC License (ISCL)
Copyright (C) 2025 Shin'ya Minazuki <shinyoukai@laidback.moe> Copyright (C) 2025-2026 Shin'ya Minazuki <shinyoukai@laidback.moe>
Permission to use, copy, modify, and/or distribute this software for any Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above purpose with or without fee is hereby granted, provided that the above

View File

@@ -5,6 +5,6 @@ VERSION ?= `git describe --tags`
REVISION ?= `git rev-list --all | wc -l` REVISION ?= `git rev-list --all | wc -l`
build: build:
@${GO} build ${GOFLAGS} -o mikuru ./cmd @${GO} build ${GOFLAGS}
clean: clean:
@rm -f mikuru @rm -f mikuru

View File

@@ -2,10 +2,13 @@
A [yarn.social](https://yarn.social) client from the future A [yarn.social](https://yarn.social) client from the future
## Current status ## Current status
* [ ] Follow/Unfollow * [X] Follow/Unfollow
* [X] Login * [X] Login
* [X] Posting * [X] Posting
* [ ] Timeline * [ ] Timeline (there's only [this shell script](mikuru-timeline) at the moment)
## Homepage
* [mikuru@projects.laidback.moe](https://projects.laidback.moe/mikuru/)
## License ## License
[ISC](COPYING) [ISC](COPYING)

View File

@@ -6,8 +6,7 @@ env:
GO: go GO: go
vars: vars:
IMPORT: git.laidback.moe/shinyoukai/mikuru IMPORT: git.laidback.moe/shinyoukai/mikuru/mirai
DIR: ./cmd
tasks: tasks:
default: default:
cmds: cmds:
@@ -15,7 +14,7 @@ tasks:
build: build:
desc: Build the client desc: Build the client
cmds: cmds:
- $GO build -ldflags='-s -w -X "{{.IMPORT}}.Version={{.VERSION}}" -X "{{.IMPORT}}.Revision={{.REVISION}}"' -v -o mikuru {{.DIR}} - $GO build -ldflags='-s -w -X "{{.IMPORT}}.Version={{.VERSION}}" -X "{{.IMPORT}}.Revision={{.REVISION}}"' -buildvcs=false -buildmode=exe -v
vars: vars:
REVISION: REVISION:
sh: git rev-list --all | wc -l | tr -d ' ' sh: git rev-list --all | wc -l | tr -d ' '

45
follow.go Normal file
View File

@@ -0,0 +1,45 @@
package main
import (
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"git.laidback.moe/shinyoukai/mikuru/mirai"
"go.yarn.social/client"
)
var followCmd = &cobra.Command{
Use: "follow <NICK> <URL>",
Short: "Track a twtxt.txt feed, located in a Yarn pod or otherwise",
Run: func(_ *cobra.Command, args []string) {
cli, err := client.NewClient(
client.WithURI(mirai.Config.Host),
client.WithToken(mirai.Config.Token),
)
if err != nil {
log.Fatal(err)
}
if len(args) != 2 {
log.Fatal("Not enough arguments")
}
nick := args[0]
url := args[1]
observe(cli, nick, url)
if err != nil {
log.Fatalf("Could not follow %s at %s\n", nick, url)
}
},
}
func init() {
mirai.ConfInit()
rootCmd.AddCommand(followCmd)
}
func observe(cli *client.Client, nick, url string) error {
err := cli.Follow(nick, url)
if err != nil {
return err
}
return nil
}

View File

@@ -7,7 +7,7 @@ import (
"golang.org/x/term" "golang.org/x/term"
"go.yarn.social/client" "go.yarn.social/client"
"git.laidback.moe/shinyoukai/mikuru" "git.laidback.moe/shinyoukai/mikuru/mirai"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@@ -20,20 +20,20 @@ var (
var loginCmd = &cobra.Command{ var loginCmd = &cobra.Command{
Use: "login", Use: "login",
Short: "Authenticate against a Yarn.social pod", Short: "Authenticate against a Yarn pod",
Aliases: []string{"auth", "signin"}, Aliases: []string{"auth", "signin"},
Args: cobra.MaximumNArgs(0), Args: cobra.MaximumNArgs(0),
Run: func(_ *cobra.Command, _ []string) { Run: func(_ *cobra.Command, _ []string) {
cli, err := client.NewClient(client.WithURI(mikuru.Config.Host)) cli, err := client.NewClient(client.WithURI(mirai.Config.Host))
if err != nil { if err != nil {
log.Fatal("Unable to create client", err) log.Fatalf("Unable to create client\n%s\n", err)
} }
signin(cli) signin(cli)
}, },
} }
func init() { func init() {
mikuru.ConfInit() mirai.ConfInit()
rootCmd.AddCommand(loginCmd) rootCmd.AddCommand(loginCmd)
} }
@@ -49,7 +49,7 @@ func signin(cli *client.Client) {
fmt.Printf("Password: ") fmt.Printf("Password: ")
data, err := term.ReadPassword(int(syscall.Stdin)) data, err := term.ReadPassword(int(syscall.Stdin))
if err != nil { if err != nil {
log.Fatal("Unable to obtain password", err) log.Fatalf("Unable to obtain password\n%s\n", err)
} }
password := string(data) password := string(data)
@@ -57,7 +57,7 @@ func signin(cli *client.Client) {
res, err := cli.Login(username, password) res, err := cli.Login(username, password)
if err != nil { if err != nil {
log.Fatal("Unable to login", err) log.Fatalf("Unable to login\n%s\n", err)
} }
token := strings.Trim(fmt.Sprintf(res.Token), "{}") token := strings.Trim(fmt.Sprintf(res.Token), "{}")

10
mikuru-timeline Executable file
View File

@@ -0,0 +1,10 @@
#!/bin/sh
# That will have to do for now
HOST="$(sed -e 's/host = //' -e '/mikuru/d' -e '/token/d' ~/.config/mikuru.ini)"
TOKEN="$(sed 's/token = //' ~/.config/mikuru.ini | tail -n1)"
curl -s \
-H "Accept: application/json" -H "Content-Type: application/json" \
-H "User-Agent: mikuru/timeline.sh" -H "Token: ${TOKEN}" \
-d '{"page": 1}' ${HOST}/api/v1/timeline \
| jq ".twts"

View File

@@ -1,4 +1,4 @@
package mikuru package mirai
import ( import (
"log" "log"

17
mirai/version.go Normal file
View File

@@ -0,0 +1,17 @@
package mirai
import (
"fmt"
)
var (
Revision = "0"
Version = "0"
)
func FullVersion() string {
return fmt.Sprintf("%s (r%s)", Version, Revision)
}
func PrintVersion() string {
return fmt.Sprintf("%s", Version)
}

View File

@@ -1,7 +1,7 @@
package main package main
import ( import (
"git.laidback.moe/shinyoukai/mikuru" "git.laidback.moe/shinyoukai/mikuru/mirai"
"go.yarn.social/client" "go.yarn.social/client"
"github.com/tj/go-editor" "github.com/tj/go-editor"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
@@ -14,11 +14,11 @@ var postCmd = &cobra.Command{
Short: "Publish a new post to a Yarn pod", Short: "Publish a new post to a Yarn pod",
Run: func(_ *cobra.Command, args []string) { Run: func(_ *cobra.Command, args []string) {
cli, err := client.NewClient( cli, err := client.NewClient(
client.WithURI(mikuru.Config.Host), client.WithURI(mirai.Config.Host),
client.WithToken(mikuru.Config.Token), client.WithToken(mirai.Config.Token),
) )
if err != nil { if err != nil {
log.Fatal("Unable to create client", err) log.Fatalf("Unable to create client\n%s\n", err)
} }
write(cli) write(cli)
}, },
@@ -26,7 +26,7 @@ var postCmd = &cobra.Command{
func init() { func init() {
rootCmd.AddCommand(postCmd) rootCmd.AddCommand(postCmd)
mikuru.ConfInit() mirai.ConfInit()
} }
func write(cli *client.Client) { func write(cli *client.Client) {
@@ -35,7 +35,7 @@ func write(cli *client.Client) {
data, err := editor.Read() data, err := editor.Read()
if err != nil { if err != nil {
log.Fatal("Unable to read content from editor", err) log.Fatalf("Unable to read content from editor\n%s\n", err)
} }
post = string(data) post = string(data)
@@ -43,6 +43,6 @@ func write(cli *client.Client) {
_, err = cli.Post(post, "") _, err = cli.Post(post, "")
if err != nil { if err != nil {
log.Fatal("Unable to publish tweet", err) log.Fatalf("Unable to publish tweet\n%s\n", err)
} }
} }

View File

@@ -3,13 +3,13 @@ package main
import ( import (
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"git.laidback.moe/shinyoukai/mikuru" "git.laidback.moe/shinyoukai/mikuru/mirai"
) )
var rootCmd = &cobra.Command{ var rootCmd = &cobra.Command{
Use: "mikuru", Use: "mikuru",
Short: "A client for Yarn.social from the future", Short: "A client for Yarn.social from the future",
Version: mikuru.Version, Version: mirai.FullVersion(),
} }
func Execute() { func Execute() {

44
unfollow.go Normal file
View File

@@ -0,0 +1,44 @@
package main
import (
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"git.laidback.moe/shinyoukai/mikuru/mirai"
"go.yarn.social/client"
)
var unfollowCmd = &cobra.Command{
Use: "unfollow <NICK>",
Short: "Cease to track a feed",
Run: func(_ *cobra.Command, args []string) {
cli, err := client.NewClient(
client.WithURI(mirai.Config.Host),
client.WithToken(mirai.Config.Token),
)
if err != nil {
log.Fatal(err)
}
if len(args) != 1 {
log.Fatal("Not enough arguments")
}
nick := args[0]
leave_alone(cli, nick)
if err != nil {
log.Fatalf("Could not unfollow %s\n", nick)
}
},
}
func init() {
mirai.ConfInit()
rootCmd.AddCommand(unfollowCmd)
}
func leave_alone(cli *client.Client, nick string) error {
err := cli.Unfollow(nick)
if err != nil {
return err
}
return nil
}

View File

@@ -1,13 +0,0 @@
package mikuru
import (
"fmt"
)
var (
Version = "0"
)
func PrintVersion() string {
return fmt.Sprintf("%s", Version)
}