commit 7d673bfa170f00f941383789e119d295c226005d Author: B4D_US3R Date: Thu Mar 6 10:12:47 2025 +0500 initial release diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..363e416 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +secret.conf +go.sum diff --git a/config.yaml b/config.yaml new file mode 100644 index 0000000..81b3139 --- /dev/null +++ b/config.yaml @@ -0,0 +1,2 @@ +instance: pleroma.catgirls.asia +rss_url: https://pleroma.catgirls.asia/users/SiberiaBread/feed.atom \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..36ff9f2 --- /dev/null +++ b/go.mod @@ -0,0 +1,25 @@ +module kiki + +go 1.21 + +require ( + github.com/go-yaml/yaml v2.1.0+incompatible + github.com/mattn/go-mastodon v0.0.9 + github.com/mmcdole/gofeed v1.3.0 + github.com/urfave/cli/v3 v3.0.0-beta1 +) + +require ( + github.com/PuerkitoBio/goquery v1.8.0 // indirect + github.com/andybalholm/cascadia v1.3.1 // indirect + github.com/gorilla/websocket v1.5.1 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/mmcdole/goxpp v1.1.1-0.20240225020742-a0c311522b23 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 // indirect + golang.org/x/net v0.25.0 // indirect + golang.org/x/text v0.15.0 // indirect + gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect +) diff --git a/main.go b/main.go new file mode 100644 index 0000000..a94dbb1 --- /dev/null +++ b/main.go @@ -0,0 +1,200 @@ +package main + +import ( + "context" + "fmt" + "log" + "net/url" + "os" + "path/filepath" + "time" + + "github.com/go-yaml/yaml" + "github.com/mattn/go-mastodon" + "github.com/mmcdole/gofeed" + "github.com/urfave/cli/v3" +) + +type MastodonClientData struct { + ClientID string `yaml:"clientID,omitempty"` + ClientSecret string `yaml:"clientSecret,omitempty"` + AccessToken string `yaml:"accessToken,omitempty"` + Instance string `yaml:"instance,omitempty"` +} + +type KikiSettings struct { + Instance string `yaml:"instance,omitempty"` + RSSUri string `yaml:"rss_url,omitempty"` +} + +func getDataFromConfig(path string) *mastodon.Config { + var clientData MastodonClientData + secretConfig, err := os.ReadFile(path) + if err != nil { + log.Println(err) + } + err = yaml.Unmarshal(secretConfig, &clientData) + if err != nil { + log.Println(err) + } + config := &mastodon.Config{ + Server: clientData.Instance, + ClientID: clientData.ClientID, + ClientSecret: clientData.ClientSecret, + AccessToken: clientData.AccessToken, + } + + return config +} + +func getKikiConfig(path string) KikiSettings { + var kikiSettings KikiSettings + kikiConfigFile, err := os.ReadFile(path) + if err != nil { + log.Println(err) + } + err = yaml.Unmarshal(kikiConfigFile, &kikiSettings) + if err != nil { + log.Println(err) + } + return kikiSettings +} + +func ClientConfiguration(Instance string) { + appConfig := &mastodon.AppConfig{ + Server: Instance, + ClientName: "Kiki", + Scopes: "read write follow", + Website: "catgirls.asia", + RedirectURIs: "urn:ietf:wg:oauth:2.0:oob", + } + app, err := mastodon.RegisterApp(context.Background(), appConfig) + if err != nil { + log.Println(err) + } + + u, err := url.Parse(app.AuthURI) + if err != nil { + log.Println(err) + } + var userToken string + fmt.Println(u) + fmt.Scanln(&userToken) + + config := &mastodon.Config{ + Server: Instance, + ClientID: app.ClientID, + ClientSecret: app.ClientSecret, + AccessToken: userToken, + } + + mastoClient := mastodon.NewClient(config) + err = mastoClient.AuthenticateToken(context.Background(), userToken, "urn:ietf:wg:oauth:2.0:oob") + if err != nil { + log.Println(err) + } + + clientData := MastodonClientData{ + Instance: Instance, + ClientID: mastoClient.Config.ClientID, + ClientSecret: mastoClient.Config.ClientSecret, + AccessToken: mastoClient.Config.AccessToken, + } + + marshaledYaml, err := yaml.Marshal(clientData) + if err != nil { + log.Println(err) + } + secretConfig, err := os.OpenFile("secret.conf", os.O_CREATE, 0o644) + if err != nil { + log.Println(err) + } + secretConfig.WriteString(string(marshaledYaml)) +} + +func newsText(url string) []*gofeed.Item { + fp := gofeed.NewParser() + feed, err := fp.ParseURL(url) + if err != nil { + log.Println(err) + } + log.Println("RSS лента получена") + return feed.Items +} + +func createPost(statusText string) { + config := getDataFromConfig("secret.conf") + + mastoClient := mastodon.NewClient(config) + + toot := mastodon.Toot{ + Status: statusText, + Visibility: "unlisted", + } + + _, err := mastoClient.PostStatus(context.Background(), &toot) + if err != nil { + log.Println(err) + } +} + +func main() { + cmd := &cli.Command{ + Name: "kiki", + Usage: "Ретранслятор из RSS в Mastodon. Когда-нибудь...", + Commands: []*cli.Command{ + { + Name: "init", + Usage: "Инициализировать клиента", + Action: func(ctx context.Context, cmd *cli.Command) error { + confFile, err := filepath.Abs("config.yaml") + if err != nil { + log.Println(err) + } + kikiConfig := getKikiConfig(confFile) + instanceUrlParser, err := url.Parse(kikiConfig.Instance) + if err != nil { + log.Println(err) + } + instanceUrlParser.Scheme = "https" + ClientConfiguration(instanceUrlParser.String()) + return nil + }, + }, + { + Name: "run", + Usage: "Запуск транслятора", + Action: func(ctx context.Context, cmd *cli.Command) error { + var lastGUID string + confFile, err := filepath.Abs("config.yaml") + if err != nil { + log.Println(err) + } + kikiConfig := getKikiConfig(confFile) + ticker := time.NewTicker(1 * time.Minute) + defer ticker.Stop() + for range ticker.C { + news := newsText(kikiConfig.RSSUri) + if news[0].GUID != lastGUID { + createPost(news[0].Description) + lastGUID = news[0].GUID + log.Println("Пост отправлен") + } + /*for _, item := range newsText(kikiConfig.RSSUri) { + if item.GUID == lastGUID { + break + } + createPost(item.Description) + lastGUID = item.GUID + log.Println("Пост отправлен") + }*/ + } + return nil + }, + }, + }, + } + if err := cmd.Run(context.Background(), os.Args); err != nil { + log.Fatal(err) + } +}