Initial Commit
This commit is contained in:
commit
68b25e0faf
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/lemmy-reply-bot
|
109
config.go
Normal file
109
config.go
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/pelletier/go-toml/v2"
|
||||||
|
"go.elara.ws/logger/log"
|
||||||
|
"go.elara.ws/pcre"
|
||||||
|
"go.elara.ws/salix"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
File *ConfigFile
|
||||||
|
PollInterval time.Duration
|
||||||
|
Regexes map[string]*pcre.Regexp
|
||||||
|
Tmpls *salix.Namespace
|
||||||
|
}
|
||||||
|
|
||||||
|
type ConfigFile struct {
|
||||||
|
Lemmy Lemmy `toml:"lemmy"`
|
||||||
|
Replies []Reply `toml:"reply"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Lemmy struct {
|
||||||
|
InstanceURL string `toml:"instance_url"`
|
||||||
|
PollInterval string `toml:"poll_interval"`
|
||||||
|
Account LemmyAccount `toml:"account"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type LemmyAccount struct {
|
||||||
|
UserOrEmail string `toml:"user_or_email"`
|
||||||
|
Password string `toml:"password"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Reply struct {
|
||||||
|
Regex string `toml:"regex"`
|
||||||
|
Template string `toml:"template"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadConfig(path string) (Config, error) {
|
||||||
|
fl, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return Config{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
fi, err := fl.Stat()
|
||||||
|
if err != nil {
|
||||||
|
return Config{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if fi.Mode().Perm() != 0o600 {
|
||||||
|
log.Fatal("Your config file's permissions are insecure. Please use chmod to set them to 600. Refusing to start.").Send()
|
||||||
|
}
|
||||||
|
|
||||||
|
cfgFile := &ConfigFile{Lemmy: Lemmy{PollInterval: "10s"}}
|
||||||
|
err = toml.NewDecoder(fl).Decode(cfgFile)
|
||||||
|
if err != nil {
|
||||||
|
return Config{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
out := Config{File: cfgFile}
|
||||||
|
|
||||||
|
out.Regexes, out.Tmpls, err = compileReplies(cfgFile.Replies)
|
||||||
|
if err != nil {
|
||||||
|
return Config{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
out.PollInterval, err = time.ParseDuration(cfgFile.Lemmy.PollInterval)
|
||||||
|
if err != nil {
|
||||||
|
return Config{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func compileReplies(replies []Reply) (map[string]*pcre.Regexp, *salix.Namespace, error) {
|
||||||
|
regexes := map[string]*pcre.Regexp{}
|
||||||
|
ns := salix.New().WithVarMap(map[string]any{
|
||||||
|
"regexReplace": regexReplace,
|
||||||
|
})
|
||||||
|
|
||||||
|
for _, reply := range replies {
|
||||||
|
if _, ok := regexes[reply.Regex]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
re, err := pcre.Compile(reply.Regex)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
regexes[reply.Regex] = re
|
||||||
|
|
||||||
|
_, err = ns.ParseString(reply.Regex, reply.Template)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return regexes, ns, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func regexReplace(str, pattern, new string) (string, error) {
|
||||||
|
re, err := pcre.Compile(pattern)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return re.ReplaceAllString(str, new), nil
|
||||||
|
}
|
51
go.mod
Normal file
51
go.mod
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
module go.elara.ws/lemmy-reply-bot
|
||||||
|
|
||||||
|
go 1.21.5
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/chaisql/chai v0.16.0
|
||||||
|
github.com/pelletier/go-toml/v2 v2.0.5
|
||||||
|
github.com/spf13/pflag v1.0.5
|
||||||
|
go.elara.ws/go-lemmy v0.19.0
|
||||||
|
go.elara.ws/logger v0.0.0-20230928062203-85e135cf02ae
|
||||||
|
go.elara.ws/pcre v0.0.0-20230805032557-4ce849193f64
|
||||||
|
go.elara.ws/salix v0.0.0-20240103024736-25037db86a10
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/DataDog/zstd v1.5.5 // indirect
|
||||||
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
|
github.com/buger/jsonparser v1.1.1 // indirect
|
||||||
|
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||||
|
github.com/cockroachdb/errors v1.11.1 // indirect
|
||||||
|
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect
|
||||||
|
github.com/cockroachdb/pebble v1.0.0 // indirect
|
||||||
|
github.com/cockroachdb/redact v1.1.5 // indirect
|
||||||
|
github.com/getsentry/sentry-go v0.25.0 // indirect
|
||||||
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
|
github.com/golang-module/carbon/v2 v2.2.14 // indirect
|
||||||
|
github.com/golang/snappy v0.0.4 // indirect
|
||||||
|
github.com/google/go-querystring v1.1.0 // indirect
|
||||||
|
github.com/google/uuid v1.3.0 // indirect
|
||||||
|
github.com/gookit/color v1.5.1 // indirect
|
||||||
|
github.com/klauspost/compress v1.17.4 // indirect
|
||||||
|
github.com/kr/pretty v0.3.1 // indirect
|
||||||
|
github.com/kr/text v0.2.0 // indirect
|
||||||
|
github.com/mattn/go-isatty v0.0.17 // indirect
|
||||||
|
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect
|
||||||
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
|
github.com/prometheus/client_golang v1.17.0 // indirect
|
||||||
|
github.com/prometheus/client_model v0.5.0 // indirect
|
||||||
|
github.com/prometheus/common v0.45.0 // indirect
|
||||||
|
github.com/prometheus/procfs v0.12.0 // indirect
|
||||||
|
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
|
||||||
|
github.com/rogpeppe/go-internal v1.11.0 // indirect
|
||||||
|
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect
|
||||||
|
golang.org/x/exp v0.0.0-20231127185646-65229373498e // indirect
|
||||||
|
golang.org/x/sys v0.15.0 // indirect
|
||||||
|
golang.org/x/text v0.14.0 // indirect
|
||||||
|
google.golang.org/protobuf v1.31.0 // indirect
|
||||||
|
modernc.org/libc v1.16.8 // indirect
|
||||||
|
modernc.org/mathutil v1.4.1 // indirect
|
||||||
|
modernc.org/memory v1.1.1 // indirect
|
||||||
|
)
|
170
go.sum
Normal file
170
go.sum
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
github.com/DataDog/zstd v1.5.5 h1:oWf5W7GtOLgp6bciQYDmhHHjdhYkALu6S/5Ni9ZgSvQ=
|
||||||
|
github.com/DataDog/zstd v1.5.5/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw=
|
||||||
|
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
|
github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
|
||||||
|
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
|
||||||
|
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||||
|
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
|
github.com/chaisql/chai v0.16.0 h1:UVvVOcf9H/OfSNRAzH9j1TuJnetUGGqV6gaAXZ8mrjQ=
|
||||||
|
github.com/chaisql/chai v0.16.0/go.mod h1:DYGursaN0/64vw3puP+ICq/sYr+TfdbKo9jmRax6J3Q=
|
||||||
|
github.com/cockroachdb/datadriven v1.0.3-0.20230801171734-e384cf455877 h1:1MLK4YpFtIEo3ZtMA5C795Wtv5VuUnrXX7mQG+aHg6o=
|
||||||
|
github.com/cockroachdb/datadriven v1.0.3-0.20230801171734-e384cf455877/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU=
|
||||||
|
github.com/cockroachdb/errors v1.11.1 h1:xSEW75zKaKCWzR3OfxXUxgrk/NtT4G1MiOv5lWZazG8=
|
||||||
|
github.com/cockroachdb/errors v1.11.1/go.mod h1:8MUxA3Gi6b25tYlFEBGLf+D8aISL+M4MIpiWMSNRfxw=
|
||||||
|
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE=
|
||||||
|
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs=
|
||||||
|
github.com/cockroachdb/pebble v1.0.0 h1:WZWlV/s78glZbY2ylUITDOWSVBD3cLjcWPLRPFbHNYg=
|
||||||
|
github.com/cockroachdb/pebble v1.0.0/go.mod h1:bynZ3gvVyhlvjLI7PT6dmZ7g76xzJ7HpxfjgkzCGz6s=
|
||||||
|
github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30=
|
||||||
|
github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg=
|
||||||
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
|
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/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||||
|
github.com/getsentry/sentry-go v0.25.0 h1:q6Eo+hS+yoJlTO3uu/azhQadsD8V+jQn2D8VvX1eOyI=
|
||||||
|
github.com/getsentry/sentry-go v0.25.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY=
|
||||||
|
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
|
||||||
|
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
|
||||||
|
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||||
|
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||||
|
github.com/golang-module/carbon/v2 v2.2.14 h1:mT2hpNoCQVnkboZ6iyRf7WCbXtZTRXFBvXXWMp0PaMc=
|
||||||
|
github.com/golang-module/carbon/v2 v2.2.14/go.mod h1:XDALX7KgqmHk95xyLeaqX9/LJGbfLATyruTziq68SZ8=
|
||||||
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
|
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||||
|
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
|
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||||
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
|
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
||||||
|
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
|
||||||
|
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||||
|
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/gookit/color v1.5.1 h1:Vjg2VEcdHpwq+oY63s/ksHrgJYCTo0bwWvmmYWdE9fQ=
|
||||||
|
github.com/gookit/color v1.5.1/go.mod h1:wZFzea4X8qN6vHOSP2apMb4/+w/orMznEzYsIHPaqKM=
|
||||||
|
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
|
||||||
|
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||||
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
|
github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4=
|
||||||
|
github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
|
||||||
|
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
|
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||||
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
|
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||||
|
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
|
||||||
|
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||||
|
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg=
|
||||||
|
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k=
|
||||||
|
github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg=
|
||||||
|
github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas=
|
||||||
|
github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4=
|
||||||
|
github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
|
||||||
|
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||||
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q=
|
||||||
|
github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY=
|
||||||
|
github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
|
||||||
|
github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
|
||||||
|
github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM=
|
||||||
|
github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY=
|
||||||
|
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
|
||||||
|
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
|
||||||
|
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
|
||||||
|
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||||
|
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||||
|
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
|
||||||
|
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
|
||||||
|
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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
|
||||||
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
|
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||||
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
|
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8=
|
||||||
|
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs=
|
||||||
|
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
go.elara.ws/go-lemmy v0.19.0 h1:FdPfiA+8yOa2IhrLdBp8jdYbnY6H55bfwnBbiGr0OHg=
|
||||||
|
go.elara.ws/go-lemmy v0.19.0/go.mod h1:aZbF/4c1VA7qPXsP4Pth0ERu3HGZFPPl8bTY1ltBrcQ=
|
||||||
|
go.elara.ws/logger v0.0.0-20230928062203-85e135cf02ae h1:d+gJUhEWSrOjrrfgeydYWEr8TTnx0DLvcVhghaOsFeE=
|
||||||
|
go.elara.ws/logger v0.0.0-20230928062203-85e135cf02ae/go.mod h1:qng49owViqsW5Aey93lwBXONw20oGbJIoLVscB16mPM=
|
||||||
|
go.elara.ws/pcre v0.0.0-20230805032557-4ce849193f64 h1:QixGnJE1jP08Hs1G3rS7tZGd8DeBRtz9RBpk08WlGh4=
|
||||||
|
go.elara.ws/pcre v0.0.0-20230805032557-4ce849193f64/go.mod h1:EF48C6VnP4wBayzFGk6lXqbiLucH7EfiaYOgiiCe5k4=
|
||||||
|
go.elara.ws/salix v0.0.0-20240103024736-25037db86a10 h1:JOFqDTLiWO+WL/+BofQAd63pv1SfEawsGVbqnSVFf6E=
|
||||||
|
go.elara.ws/salix v0.0.0-20240103024736-25037db86a10/go.mod h1:niWia13iw7qDrS1C1mlqv5hxO1sunt8CcOQAB5yVlNU=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/exp v0.0.0-20231127185646-65229373498e h1:Gvh4YaCaXNs6dKTlfgismwWZKyjVZXwOPfIyUaqU3No=
|
||||||
|
golang.org/x/exp v0.0.0-20231127185646-65229373498e/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI=
|
||||||
|
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
|
||||||
|
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
|
||||||
|
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||||
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||||
|
golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
|
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||||
|
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
|
||||||
|
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
|
||||||
|
modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI=
|
||||||
|
modernc.org/ccgo/v3 v3.0.0-20220428102840-41399a37e894/go.mod h1:eI31LL8EwEBKPpNpA4bU1/i+sKOwOrQy8D87zWUcRZc=
|
||||||
|
modernc.org/ccgo/v3 v3.0.0-20220430103911-bc99d88307be/go.mod h1:bwdAnOoaIt8Ax9YdWGjxWsdkPcZyRPHqrOvJxaKAKGw=
|
||||||
|
modernc.org/ccgo/v3 v3.16.6/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ=
|
||||||
|
modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ=
|
||||||
|
modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM=
|
||||||
|
modernc.org/libc v0.0.0-20220428101251-2d5f3daf273b/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA=
|
||||||
|
modernc.org/libc v1.16.0/go.mod h1:N4LD6DBE9cf+Dzf9buBlzVJndKr/iJHG97vGLHYnb5A=
|
||||||
|
modernc.org/libc v1.16.1/go.mod h1:JjJE0eu4yeK7tab2n4S1w8tlWd9MxXLRzheaRnAKymU=
|
||||||
|
modernc.org/libc v1.16.8 h1:Ux98PaOMvolgoFX/YwusFOHBnanXdGRmWgI8ciI2z4o=
|
||||||
|
modernc.org/libc v1.16.8/go.mod h1:hYIV5VZczAmGZAnG15Vdngn5HSF5cSkbvfz2B7GRuVU=
|
||||||
|
modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
|
||||||
|
modernc.org/mathutil v1.4.1 h1:ij3fYGe8zBF4Vu+g0oT7mB06r8sqGWKuJu1yXeR4by8=
|
||||||
|
modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
|
||||||
|
modernc.org/memory v1.1.1 h1:bDOL0DIDLQv7bWhP3gMvIrnoFw+Eo6F7a2QK9HPDiFU=
|
||||||
|
modernc.org/memory v1.1.1/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw=
|
||||||
|
modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
|
||||||
|
modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw=
|
||||||
|
modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
|
65
internal/db/db.go
Normal file
65
internal/db/db.go
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
package db
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/chaisql/chai"
|
||||||
|
)
|
||||||
|
|
||||||
|
var db *chai.DB
|
||||||
|
|
||||||
|
// Init opens the database and applies migrations
|
||||||
|
func Init(path string) error {
|
||||||
|
g, err := chai.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
db = g
|
||||||
|
return db.Exec(`
|
||||||
|
CREATE TABLE IF NOT EXISTS replied_items (
|
||||||
|
id INT NOT NULL PRIMARY KEY,
|
||||||
|
reply_id INT NOT NULL,
|
||||||
|
item_type TEXT NOT NULL CHECK ( item_type IN ['post', 'comment'] ),
|
||||||
|
updated TIMESTAMP NOT NULL,
|
||||||
|
UNIQUE(id, item_type)
|
||||||
|
)
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Close() error {
|
||||||
|
return db.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
type ItemType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
Post ItemType = "post"
|
||||||
|
Comment ItemType = "comment"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Item struct {
|
||||||
|
ID int64 `chai:"id"`
|
||||||
|
ReplyID int64 `chai:"reply_id"`
|
||||||
|
ItemType ItemType `chai:"item_type"`
|
||||||
|
Updated time.Time `chai:"updated"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddItem(i Item) error {
|
||||||
|
return db.Exec(`INSERT INTO replied_items VALUES ?`, &i)
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetUpdatedTime(id int64, itemType ItemType, updated time.Time) error {
|
||||||
|
return db.Exec(`UPDATE replied_items SET updated = ? WHERE id = ? AND item_type = ?`, updated, id, itemType)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetItem(id int64, itemType ItemType) (*Item, error) {
|
||||||
|
row, err := db.QueryRow(`SELECT * FROM replied_items WHERE id = ? AND item_type = ?`, id, itemType)
|
||||||
|
if chai.IsNotFoundError(err) {
|
||||||
|
return nil, nil
|
||||||
|
} else if err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
out := &Item{}
|
||||||
|
return out, row.StructScan(out)
|
||||||
|
}
|
||||||
|
}
|
54
lemmy-reply-bot.example.toml
Normal file
54
lemmy-reply-bot.example.toml
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
[lemmy]
|
||||||
|
instance_url = "https://lemmy.ml"
|
||||||
|
poll_interval = "10s"
|
||||||
|
|
||||||
|
[lemmy.account]
|
||||||
|
user_or_email = "user@example.com"
|
||||||
|
password = "ExamplePassword123"
|
||||||
|
|
||||||
|
# Replies to any message starting with "!!BOT_TEST", with some information
|
||||||
|
# about what it's replying to
|
||||||
|
#
|
||||||
|
# Example: !!BOT_TEST Hello :3
|
||||||
|
[[reply]]
|
||||||
|
regex = "!!BOT_TEST (.+)"
|
||||||
|
template = '''
|
||||||
|
ID: #(id) \
|
||||||
|
Type: #(type) \
|
||||||
|
Content: #(matches[0][1])
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
# Returns archive links for URLs preceded with "!archive"
|
||||||
|
#
|
||||||
|
# Example: !archive https://gitea.elara.ws/Elara6331/lemmy-reply-bot
|
||||||
|
[[reply]]
|
||||||
|
regex = '!archive (https?)://([.\w\d]+\.[\w\d]{2,4}[\w\d?&=%/.-]*)'
|
||||||
|
msg = '''
|
||||||
|
Here are the archive links you requested:
|
||||||
|
|
||||||
|
#for(i, match in matches):
|
||||||
|
#if(len(matches) > 1):Link #(i+1):#!if
|
||||||
|
- [archive.vn](https://archive.vn/#(match[1])://#(match[2]))
|
||||||
|
- [archive.org](https://web.archive.org/web/#(match[1])://#(match[2]))
|
||||||
|
- [ghostarchive.org](https://ghostarchive.org/search?term=#(match[1])://#(match[2]))
|
||||||
|
|
||||||
|
#!for
|
||||||
|
'''
|
||||||
|
|
||||||
|
# Returns invidious links for YouTube URLs
|
||||||
|
#
|
||||||
|
# Example: https://www.youtube.com/watch?v=2vPhySbRETM
|
||||||
|
[[reply]]
|
||||||
|
regex = 'https?://(?:(?:www|m)\.)?youtu(?:\.be/|be\.com/(?:watch\?v=|shorts/))([\w\d-]{11})[&?]?([\w\d?&=%/-]*)'
|
||||||
|
msg = '''
|
||||||
|
#(len(matches) == 1 ? "A YouTube link was" : "YouTube links were") detected in your #(type). Here are links to the same #(len(matches) == 1 ? "video" : "videos") on Invidious, which is a YouTube frontend that protects your privacy:
|
||||||
|
|
||||||
|
#for(i, match in matches):
|
||||||
|
#if(len(matches) > 1):Link #(i+1):#!if
|
||||||
|
- [yewtu.be](https://yewtu.be/watch?v=$(match[1])&#(match[2]))
|
||||||
|
- [invidious.weblibre.org](https://invidious.weblibre.org/watch?v=#(match[1])&#(match[2]))
|
||||||
|
- [inv.vern.cc](https://inv.vern.cc/watch?v=#(match[1])&#(match[2]))
|
||||||
|
|
||||||
|
#!for
|
||||||
|
'''
|
288
main.go
Normal file
288
main.go
Normal file
@ -0,0 +1,288 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/spf13/pflag"
|
||||||
|
"go.elara.ws/go-lemmy"
|
||||||
|
"go.elara.ws/lemmy-reply-bot/internal/db"
|
||||||
|
"go.elara.ws/logger"
|
||||||
|
"go.elara.ws/logger/log"
|
||||||
|
"go.elara.ws/salix"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
log.Logger = logger.NewPretty(os.Stderr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
cfgPath := pflag.StringP("config-path", "c", "/etc/lemmy-reply-bot/config.toml", "Path to the config file")
|
||||||
|
dbPath := pflag.StringP("db-path", "d", "/etc/lemmy-reply-bot/replies", "Path to the ChaiSQL database")
|
||||||
|
pflag.Parse()
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
ctx, cancel := signal.NotifyContext(ctx, os.Interrupt, syscall.SIGTERM)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
err := db.Init(*dbPath)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("Error initializing database").Err(err).Send()
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg, err := loadConfig(*cfgPath)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("Error loading config").Err(err).Send()
|
||||||
|
}
|
||||||
|
|
||||||
|
c, err := lemmy.New(cfg.File.Lemmy.InstanceURL)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("Error creating new lemmy client").Err(err).Send()
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.ClientLogin(ctx, lemmy.Login{
|
||||||
|
UsernameOrEmail: cfg.File.Lemmy.Account.UserOrEmail,
|
||||||
|
Password: cfg.File.Lemmy.Account.Password,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("Error logging into lemmy").Err(err).Send()
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("Successfully logged in!").Send()
|
||||||
|
|
||||||
|
go poll(ctx, cfg, c)
|
||||||
|
|
||||||
|
<-ctx.Done()
|
||||||
|
_ = db.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func poll(ctx context.Context, cfg Config, c *lemmy.Client) {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-time.After(cfg.PollInterval):
|
||||||
|
// Get 20 of the newest comments from Lemmy
|
||||||
|
comments, err := c.Comments(ctx, lemmy.GetComments{
|
||||||
|
Type: lemmy.NewOptional(lemmy.ListingTypeLocal),
|
||||||
|
Sort: lemmy.NewOptional(lemmy.CommentSortTypeNew),
|
||||||
|
Limit: lemmy.NewOptional[int64](20),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Warn("Error getting comments").Err(err).Send()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
handleComments(ctx, comments.Comments, cfg, c)
|
||||||
|
|
||||||
|
// Get 20 of the newest comments from Lemmy
|
||||||
|
posts, err := c.Posts(ctx, lemmy.GetPosts{
|
||||||
|
Type: lemmy.NewOptional(lemmy.ListingTypeLocal),
|
||||||
|
Sort: lemmy.NewOptional(lemmy.SortTypeNew),
|
||||||
|
Limit: lemmy.NewOptional[int64](20),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Warn("Error getting posts").Err(err).Send()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
handlePosts(ctx, posts.Posts, cfg, c)
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleComments(ctx context.Context, comments []lemmy.CommentView, cfg Config, c *lemmy.Client) {
|
||||||
|
for _, comment := range comments {
|
||||||
|
if !comment.Community.Local {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
item, err := db.GetItem(comment.Comment.ID, db.Comment)
|
||||||
|
if err != nil {
|
||||||
|
log.Warn("Error getting comment from db").Err(err).Send()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
edit := false
|
||||||
|
if item == nil {
|
||||||
|
// If the item is nil, it doesn't exist, which means we need to
|
||||||
|
// create a new reply, so we don't set edit to true in this case.
|
||||||
|
} else if item.Updated.Equal(comment.Comment.Updated) {
|
||||||
|
// If the item exists but hasn't been edited since we've last seen it,
|
||||||
|
// we can skip it since we've already replied to it.
|
||||||
|
continue
|
||||||
|
} else if item.Updated.Before(comment.Comment.Updated) {
|
||||||
|
// If the item exists and has been edited since we've last seen it,
|
||||||
|
// we need to edit it, so we set edit to true.
|
||||||
|
edit = true
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, reply := range cfg.File.Replies {
|
||||||
|
re := cfg.Regexes[reply.Regex]
|
||||||
|
if !re.MatchString(comment.Comment.Content) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("Matched comment body").
|
||||||
|
Int("reply-index", i).
|
||||||
|
Int64("comment-id", comment.Comment.ID).
|
||||||
|
Send()
|
||||||
|
|
||||||
|
matches := re.FindAllStringSubmatch(comment.Comment.Content, -1)
|
||||||
|
content, err := executeTmpl(cfg.Tmpls, reply.Regex, map[string]any{
|
||||||
|
"id": comment.Comment.ID,
|
||||||
|
"type": db.Comment,
|
||||||
|
"matches": matches,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Warn("Error executing template").Int("index", i).Err(err).Send()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if edit {
|
||||||
|
_, err = c.EditComment(ctx, lemmy.EditComment{
|
||||||
|
CommentID: item.ReplyID,
|
||||||
|
Content: lemmy.NewOptional(content),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Warn("Error editing comment").Int64("id", item.ReplyID).Err(err).Send()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("Edited comment").Int64("parent-id", item.ID).Int64("reply-id", item.ReplyID).Send()
|
||||||
|
|
||||||
|
err = db.SetUpdatedTime(comment.Comment.ID, db.Comment, comment.Comment.Updated)
|
||||||
|
if err != nil {
|
||||||
|
log.Warn("Error setting new updated time").Int64("id", item.ReplyID).Err(err).Send()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cr, err := c.CreateComment(ctx, lemmy.CreateComment{
|
||||||
|
PostID: comment.Comment.PostID,
|
||||||
|
Content: content,
|
||||||
|
ParentID: lemmy.NewOptional(comment.Comment.ID),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Warn("Error creating reply").Int64("comment-id", comment.Comment.ID).Err(err).Send()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("Created comment").Int64("parent-id", comment.Comment.ID).Int64("reply-id", cr.CommentView.Comment.ID).Send()
|
||||||
|
|
||||||
|
err = db.AddItem(db.Item{
|
||||||
|
ID: comment.Comment.ID,
|
||||||
|
ReplyID: cr.CommentView.Comment.ID,
|
||||||
|
ItemType: db.Comment,
|
||||||
|
Updated: comment.Comment.Updated,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Warn("Error adding reply to database").Int64("id", item.ReplyID).Err(err).Send()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func handlePosts(ctx context.Context, posts []lemmy.PostView, cfg Config, c *lemmy.Client) {
|
||||||
|
for _, post := range posts {
|
||||||
|
if !post.Community.Local {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
item, err := db.GetItem(post.Post.ID, db.Post)
|
||||||
|
if err != nil {
|
||||||
|
log.Warn("Error getting comment from db").Err(err).Send()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
edit := false
|
||||||
|
if item == nil {
|
||||||
|
// If the item is nil, it doesn't exist, which means we need to
|
||||||
|
// reply to it, so we don't set edit to true in this case.
|
||||||
|
} else if item.Updated.Equal(post.Post.Updated) {
|
||||||
|
// If the item exists but hasn't been edited since we've last seen it,
|
||||||
|
// we can skip it since we've already replied to it.
|
||||||
|
continue
|
||||||
|
} else if item.Updated.Before(post.Post.Updated) {
|
||||||
|
// If the item exists and has been edited since we've last seen it,
|
||||||
|
// we need to edit it, so we set edit to true.
|
||||||
|
edit = true
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, reply := range cfg.File.Replies {
|
||||||
|
re := cfg.Regexes[reply.Regex]
|
||||||
|
content := post.Post.URL.ValueOrZero() + "\n\n" + post.Post.Body.ValueOrZero()
|
||||||
|
if !re.MatchString(content) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("Matched post body").
|
||||||
|
Int("reply-index", i).
|
||||||
|
Int64("post-id", post.Post.ID).
|
||||||
|
Send()
|
||||||
|
|
||||||
|
matches := re.FindAllStringSubmatch(content, -1)
|
||||||
|
content, err := executeTmpl(cfg.Tmpls, reply.Regex, map[string]any{
|
||||||
|
"id": post.Post.ID,
|
||||||
|
"type": db.Post,
|
||||||
|
"matches": matches,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Warn("Error executing template").Int("index", i).Err(err).Send()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if edit {
|
||||||
|
_, err = c.EditComment(ctx, lemmy.EditComment{
|
||||||
|
CommentID: item.ReplyID,
|
||||||
|
Content: lemmy.NewOptional(content),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Warn("Error editing post").Int64("id", item.ReplyID).Err(err).Send()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("Edited comment").Int64("post-id", item.ID).Int64("reply-id", item.ReplyID).Send()
|
||||||
|
|
||||||
|
err = db.SetUpdatedTime(post.Post.ID, db.Post, post.Post.Updated)
|
||||||
|
if err != nil {
|
||||||
|
log.Warn("Error setting new updated time").Int64("id", item.ReplyID).Err(err).Send()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cr, err := c.CreateComment(ctx, lemmy.CreateComment{
|
||||||
|
PostID: post.Post.ID,
|
||||||
|
Content: content,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Warn("Error creating reply").Int64("post-id", post.Post.ID).Err(err).Send()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("Created comment").Int64("post-id", post.Post.ID).Int64("reply-id", cr.CommentView.Comment.ID).Send()
|
||||||
|
|
||||||
|
err = db.AddItem(db.Item{
|
||||||
|
ID: post.Post.ID,
|
||||||
|
ReplyID: cr.CommentView.Comment.ID,
|
||||||
|
ItemType: db.Post,
|
||||||
|
Updated: post.Post.Updated,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Warn("Error adding reply to database").Int64("id", item.ReplyID).Err(err).Send()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func executeTmpl(ns *salix.Namespace, name string, vars map[string]any) (string, error) {
|
||||||
|
sb := &strings.Builder{}
|
||||||
|
err := ns.ExecuteTemplate(sb, name, vars)
|
||||||
|
return sb.String(), err
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user