Compare commits
No commits in common. "9d62be08692bf7cb28c9279f3ac5571982d808c8" and "3882939bc5d6a5c536617eeaa411e70c64f81573" have entirely different histories.
9d62be0869
...
3882939bc5
|
@ -1,3 +0,0 @@
|
|||
.git
|
||||
bible_databases
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
[submodule "bible_databases"]
|
||||
path = bible_databases
|
||||
url = https://github.com/scrollmapper/bible_databases.git
|
24
Dockerfile
24
Dockerfile
|
@ -1,24 +0,0 @@
|
|||
FROM golang:1.16-buster AS build
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY go.mod ./
|
||||
COPY go.sum ./
|
||||
|
||||
ENV CGO_ENABLED 0
|
||||
|
||||
RUN go mod download
|
||||
|
||||
COPY *.go ./
|
||||
|
||||
RUN go build -o /biblebot *.go
|
||||
|
||||
##
|
||||
## Deploy
|
||||
##
|
||||
FROM alpine
|
||||
|
||||
WORKDIR /
|
||||
COPY --from=build /biblebot /biblebot
|
||||
|
||||
ENTRYPOINT ["/biblebot"]
|
23
README.md
23
README.md
|
@ -1,23 +0,0 @@
|
|||
# BibleBot
|
||||
|
||||
## Setup
|
||||
|
||||
BibleBot relies on [scrollmapper/bible_databases](https://github.com/scrollmapper/bible_databases.git) for references. Download the databases with:
|
||||
```
|
||||
git submodule init
|
||||
git submodule update
|
||||
```
|
||||
Ensure Docker and docker-compose are installed
|
||||
|
||||
Create a file called `.env` and add the following to it:
|
||||
```
|
||||
RDRAMA_API_TOKEN=
|
||||
RDRAMA_URL=https://rdrama.net
|
||||
MARIADB_RANDOM_ROOT_PASSWORD=yes
|
||||
MARIADB_USER=admin
|
||||
MARIADB_PASSWORD=mysafeadminpassword
|
||||
MARIADB_DATABASE=bible
|
||||
BIBLEDB_HOST=bibledb
|
||||
BIBLEBOT_ID=
|
||||
```
|
||||
Fill in your `RDRAMA_API_TOKEN` and `BIBLEBOT_ID`. You can change the user and password.
|
81
bible.go
81
bible.go
|
@ -11,75 +11,6 @@ var BibleRegex = regexp.MustCompile(`(?P<prefix>\w*?)? *(?P<book>[a-zA-Z]+?)\s?(
|
|||
|
||||
var MatchError = errors.New("Error matching verse")
|
||||
|
||||
var CanonicalName = map[int]string{
|
||||
1: "Genesis",
|
||||
2: "Exodus",
|
||||
3: "Leviticus",
|
||||
4: "Numbers",
|
||||
5: "Deuteronomy",
|
||||
6: "Joshua",
|
||||
7: "Judges",
|
||||
8: "Ruth",
|
||||
9: "1 Samuel",
|
||||
10: "2 Samuel",
|
||||
11: "1 Kings",
|
||||
12: "2 Kings",
|
||||
13: "1 Chronicles",
|
||||
14: "2 Chronicles",
|
||||
15: "Ezra",
|
||||
16: "Nehemiah",
|
||||
17: "Esther",
|
||||
18: "Job",
|
||||
19: "Psalms",
|
||||
20: "Proverbs",
|
||||
21: "Ecclesiastes",
|
||||
22: "Song of Solomon",
|
||||
23: "Isaiah",
|
||||
24: "Jeremiah",
|
||||
25: "Lamentations",
|
||||
26: "Ezekiel",
|
||||
27: "Daniel",
|
||||
28: "Hosea",
|
||||
29: "Joel",
|
||||
30: "Amos",
|
||||
31: "Obadiah",
|
||||
32: "Jonah",
|
||||
33: "Micah",
|
||||
34: "Nahum",
|
||||
35: "Habakkuk",
|
||||
36: "Zephaniah",
|
||||
37: "Haggai",
|
||||
38: "Zechariah",
|
||||
39: "Malachi",
|
||||
40: "Matthew",
|
||||
41: "Mark",
|
||||
42: "Luke",
|
||||
43: "John",
|
||||
44: "Acts",
|
||||
45: "Romans",
|
||||
46: "1 Corinthians",
|
||||
47: "2 Corinthians",
|
||||
48: "Galatians",
|
||||
49: "Ephesians",
|
||||
50: "Philippians",
|
||||
51: "Colossians",
|
||||
52: "1 Thessalonians",
|
||||
53: "2 Thessalonians",
|
||||
54: "1 Timothy",
|
||||
55: "2 Timothy",
|
||||
56: "Titus",
|
||||
57: "Philemon",
|
||||
58: "Hebrews",
|
||||
59: "James",
|
||||
60: "1 Peter",
|
||||
61: "2 Peter",
|
||||
62: "1 John",
|
||||
63: "2 John",
|
||||
64: "3 John",
|
||||
65: "Jude",
|
||||
66: "Revelation",
|
||||
}
|
||||
|
||||
var Books = map[string]int{
|
||||
"GEN": 1,
|
||||
"EXO": 2,
|
||||
|
@ -227,17 +158,6 @@ func contains(s []string, str string) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (b *BibleReference) CanonicalName() (string, error) {
|
||||
book, ok := CanonicalName[b.BookNum]
|
||||
if !ok {
|
||||
return "", errors.New("Can't find book, maybe you're Catholic?")
|
||||
}
|
||||
if b.StartKey == b.EndKey {
|
||||
return fmt.Sprintf("%s %s:%s", book, b.Chapter, b.StartVerse), nil
|
||||
}
|
||||
return fmt.Sprintf("%s %s:%s-%s", book, b.Chapter, b.StartVerse, b.EndVerse), nil
|
||||
}
|
||||
|
||||
func (b *BibleReference) Validate() error {
|
||||
if contains(FirstPrefixes, b.Prefix) {
|
||||
b.Prefix = "1"
|
||||
|
@ -259,7 +179,6 @@ func (b *BibleReference) Validate() error {
|
|||
if !ok {
|
||||
return MatchError
|
||||
}
|
||||
b.BookNum = num
|
||||
|
||||
chapter, err := strconv.Atoi(b.Chapter)
|
||||
if err != nil {
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
Subproject commit af7500915bfd465e6da01dc37753237fd1fd416d
|
|
@ -1,31 +0,0 @@
|
|||
version: '3'
|
||||
|
||||
#
|
||||
# Docker Compose configuration for MariaDB
|
||||
#
|
||||
# To start the MariaDB instance and import the Bible data: docker-compose up
|
||||
#
|
||||
# To connect to the database from the host (presuming you have mysql-client or
|
||||
# mariadb-client installed), use a command like this:
|
||||
# mysql -h 127.0.0.1 -u root -p bible
|
||||
#
|
||||
# More information about Docker Compose: https://docs.docker.com/compose/
|
||||
#
|
||||
|
||||
services:
|
||||
bibledb:
|
||||
image: mariadb:10.5
|
||||
volumes:
|
||||
- ./bible_databases/sql:/docker-entrypoint-initdb.d
|
||||
env_file: ['.env']
|
||||
restart: always
|
||||
|
||||
biblebot:
|
||||
build:
|
||||
context: .
|
||||
env_file: ['.env']
|
||||
depends_on:
|
||||
- bibledb
|
||||
volumes:
|
||||
- ./lastrun.txt:/lastrun.txt
|
||||
# restart: unless-stopped
|
5
go.mod
5
go.mod
|
@ -1,5 +0,0 @@
|
|||
module fsdfsd.net/GeneralHurricane/BibleBot
|
||||
|
||||
go 1.15
|
||||
|
||||
require github.com/go-sql-driver/mysql v1.7.0
|
2
go.sum
2
go.sum
|
@ -1,2 +0,0 @@
|
|||
github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
|
||||
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
210
main.go
210
main.go
|
@ -1,39 +1,14 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
)
|
||||
|
||||
const NAME string = "Tʜᴇ Lᴏʀᴅ"
|
||||
|
||||
var BibleDB *sql.DB
|
||||
var BibleQuery *sql.Stmt
|
||||
var Client *RDramaClient
|
||||
var WAIT_TIME time.Duration
|
||||
var ONE_SEC time.Duration
|
||||
var BibleBotID int
|
||||
|
||||
func main() {
|
||||
ERRCOUNT := 0
|
||||
WAIT_TIME, err := time.ParseDuration("1m")
|
||||
if err != nil {
|
||||
log.Fatal("Error parsing time")
|
||||
}
|
||||
time.Sleep(WAIT_TIME)
|
||||
ONE_SEC, err = time.ParseDuration("1s")
|
||||
if err != nil {
|
||||
log.Fatal("Error parsing time 2")
|
||||
}
|
||||
|
||||
fmt.Printf("Running...\n")
|
||||
siteURL := os.Getenv("RDRAMA_URL")
|
||||
if siteURL == "" {
|
||||
|
@ -45,191 +20,24 @@ func main() {
|
|||
log.Fatal("RDRAMA_API_TOKEN environment variable not set")
|
||||
}
|
||||
|
||||
botId := os.Getenv("BIBLEBOT_ID")
|
||||
if botId == "" {
|
||||
log.Fatal("BIBLEBOT_ID environment variable not set")
|
||||
}
|
||||
BibleBotID, err = strconv.Atoi(botId)
|
||||
if err != nil {
|
||||
log.Fatal("Error loading BIBLEBOT_ID: ", botId)
|
||||
}
|
||||
|
||||
Client = NewRDramaClient(siteURL, siteToken)
|
||||
|
||||
username := os.Getenv("MARIADB_USER")
|
||||
password := os.Getenv("MARIADB_PASSWORD")
|
||||
host := os.Getenv("BIBLEDB_HOST")
|
||||
database := os.Getenv("MARIADB_DATABASE")
|
||||
|
||||
for ERRCOUNT < 5 {
|
||||
BibleDB, err = sql.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s)/%s", username, password, host, database))
|
||||
if err != nil {
|
||||
fmt.Println("ERROR connecting: ", err)
|
||||
fmt.Println("DB string: ", fmt.Sprintf("%s:%s@tcp(%s)/%s", username, password, host, database))
|
||||
ERRCOUNT = ERRCOUNT + 1
|
||||
time.Sleep(WAIT_TIME)
|
||||
} else {
|
||||
ERRCOUNT = 0
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
defer BibleDB.Close()
|
||||
BibleQuery, err = BibleDB.Prepare("SELECT t FROM t_web WHERE id BETWEEN ? AND ?")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
log.Fatal("Unable to prepare query")
|
||||
}
|
||||
defer BibleQuery.Close()
|
||||
|
||||
client := NewRDramaClient(siteURL, siteToken)
|
||||
now := time.Now()
|
||||
lastrun := time.Date(now.Year(), now.Month(), now.Day(), now.Hour()-1, 0, 0, 0, time.UTC)
|
||||
file, err := os.Open("lastrun.txt")
|
||||
if err == nil {
|
||||
|
||||
// Create a new scanner to read the file
|
||||
scanner := bufio.NewScanner(file)
|
||||
|
||||
// Read the first line of the file
|
||||
scanner.Scan()
|
||||
line := scanner.Text()
|
||||
// Convert the line to an integer
|
||||
num, err := strconv.ParseInt(line, 10, 64)
|
||||
if err == nil {
|
||||
|
||||
newTime := time.Unix(num, 0)
|
||||
// fmt.Println("New time: ", newTime)
|
||||
if newTime != time.Unix(0, 0) {
|
||||
lastrun = newTime
|
||||
}
|
||||
} else {
|
||||
fmt.Println("error parsing time", err)
|
||||
}
|
||||
file.Close()
|
||||
} else {
|
||||
fmt.Println("Err opening lastrun: ", err)
|
||||
}
|
||||
|
||||
for ERRCOUNT < 5 {
|
||||
fmt.Println("\n\n-------------------------------------------------------")
|
||||
fmt.Printf("Posts between %v - %v\n", lastrun, now)
|
||||
posts, err := Client.GetPosts(SearchParams{
|
||||
comments, err := client.GetComments(SearchParams{
|
||||
Hole: "dankchristianmemes",
|
||||
After: lastrun,
|
||||
Before: now,
|
||||
After: time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.UTC),
|
||||
})
|
||||
|
||||
if err == nil {
|
||||
|
||||
fmt.Printf("Found posts: %d\n", len(posts))
|
||||
|
||||
for _, post := range posts {
|
||||
// fmt.Printf("%s: %s\n", comment.AuthorName, comment.Text)
|
||||
if post.Author.ID != BibleBotID { // originally forgot this lol
|
||||
handleAndReply(fmt.Sprintf("%s\n%s", post.Title, post.Text), fmt.Sprintf("p_%v", post.ID))
|
||||
} else {
|
||||
fmt.Println("Skipping own post")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ERRCOUNT = ERRCOUNT + 1
|
||||
time.Sleep(ONE_SEC)
|
||||
continue
|
||||
|
||||
}
|
||||
fmt.Printf("Comments between %v - %v\n", lastrun, now)
|
||||
comments, err := Client.GetComments(SearchParams{
|
||||
Hole: "dankchristianmemes",
|
||||
After: lastrun,
|
||||
Before: now,
|
||||
})
|
||||
|
||||
if err == nil {
|
||||
|
||||
fmt.Printf("Found comments: %d\n", len(comments))
|
||||
|
||||
for _, comment := range comments {
|
||||
// fmt.Printf("%s: %s\n", comment.AuthorName, comment.Text)
|
||||
if comment.Author.ID != BibleBotID {
|
||||
handleAndReply(comment.Text, fmt.Sprintf("c_%v", comment.ID))
|
||||
} else {
|
||||
fmt.Println("Skipping own comment")
|
||||
}
|
||||
// Client.UpvoteComment(comment.ID) // not allowed for bots
|
||||
|
||||
}
|
||||
lastrun = now.Add(ONE_SEC)
|
||||
file, err = os.Create("lastrun.txt")
|
||||
if err == nil {
|
||||
_, err = file.WriteString(strconv.FormatInt(lastrun.Unix(), 10))
|
||||
if err != nil {
|
||||
fmt.Println("FILE ERROR: ", err)
|
||||
}
|
||||
err = file.Sync()
|
||||
if err != nil {
|
||||
fmt.Println("FILE ERROR: ", err)
|
||||
// fmt.Printf("%s: %s\n", comment.Author, comment.Text)
|
||||
_ = GetReferences(strings.ToUpper(comment.Text))
|
||||
}
|
||||
|
||||
file.Close()
|
||||
}
|
||||
if err != nil {
|
||||
fmt.Println("FILE ERROR: ", err)
|
||||
}
|
||||
|
||||
} else {
|
||||
ERRCOUNT = ERRCOUNT + 1
|
||||
if ERRCOUNT > 4 {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
time.Sleep(WAIT_TIME)
|
||||
now = time.Now()
|
||||
}
|
||||
}
|
||||
|
||||
func handleAndReply(text string, parent_fullname string) {
|
||||
|
||||
refs := GetReferences(strings.ToUpper(text))
|
||||
if len(refs) == 0 {
|
||||
return
|
||||
}
|
||||
var post strings.Builder
|
||||
|
||||
for _, ref := range refs {
|
||||
rows, err := BibleQuery.Query(ref.StartKey, ref.EndKey)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
continue
|
||||
}
|
||||
canName, err := ref.CanonicalName()
|
||||
post.WriteString("**")
|
||||
if err != nil {
|
||||
post.WriteString(ref.RegexMatch)
|
||||
} else {
|
||||
post.WriteString(canName)
|
||||
}
|
||||
post.WriteString("**\n> ")
|
||||
for rows.Next() {
|
||||
var verse string
|
||||
err = rows.Scan(&verse)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
continue
|
||||
}
|
||||
verse = strings.ReplaceAll(verse, "Yahweh", NAME)
|
||||
verse = strings.ReplaceAll(verse, "\n", "\n> ")
|
||||
post.WriteString(verse)
|
||||
post.WriteString(" ")
|
||||
}
|
||||
rows.Close()
|
||||
post.WriteString("\n\n")
|
||||
}
|
||||
fmt.Println(post.String())
|
||||
|
||||
err := Client.PostComment(post.String(), parent_fullname)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
} else {
|
||||
time.Sleep(ONE_SEC)
|
||||
}
|
||||
// Use the client to make API requests
|
||||
}
|
||||
|
|
101
rdrama.go
101
rdrama.go
|
@ -1,12 +1,10 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
neturl "net/url"
|
||||
"net/url"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -22,20 +20,15 @@ func NewRDramaClient(baseURL, apiKey string) *RDramaClient {
|
|||
}
|
||||
}
|
||||
|
||||
func (c *RDramaClient) makeRequest(method, path string, body string, response interface{}) error {
|
||||
func (c *RDramaClient) makeRequest(method, path string, v interface{}) error {
|
||||
url := c.baseURL + path
|
||||
var reader io.Reader
|
||||
|
||||
reader = bytes.NewBufferString(body)
|
||||
|
||||
req, err := http.NewRequest(method, url, reader)
|
||||
req, err := http.NewRequest(method, url, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req.Header.Add("Authorization", fmt.Sprintf("%s", c.apiKey))
|
||||
if body != "" {
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
}
|
||||
|
||||
client := http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
|
@ -44,71 +37,28 @@ func (c *RDramaClient) makeRequest(method, path string, body string, response in
|
|||
defer resp.Body.Close()
|
||||
|
||||
if !(resp.StatusCode >= 200 && resp.StatusCode < 300) {
|
||||
fmt.Println("request:\n", req)
|
||||
return fmt.Errorf("unexpected status code: %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
if response != nil {
|
||||
return json.NewDecoder(resp.Body).Decode(response)
|
||||
}
|
||||
// fmt.Println("reponse: ")
|
||||
// _, err = io.Copy(os.Stdout, resp.Body)
|
||||
if err != nil {
|
||||
fmt.Println("Error copyng response body: ", err)
|
||||
// handle the error
|
||||
}
|
||||
return nil
|
||||
return json.NewDecoder(resp.Body).Decode(v)
|
||||
}
|
||||
|
||||
type CommentResponse struct {
|
||||
Data []Comment `json:"data"`
|
||||
}
|
||||
|
||||
type PostResponse struct {
|
||||
Data []Post `json:"data"`
|
||||
}
|
||||
|
||||
type Comment struct {
|
||||
ID int `json:"id"`
|
||||
Author Author `json:"author"`
|
||||
AuthorName string `json:"author_name"`
|
||||
Author string `json:"author_name"`
|
||||
Text string `json:"body"`
|
||||
}
|
||||
|
||||
type Author struct {
|
||||
ID int `json:id`
|
||||
}
|
||||
|
||||
type Post struct {
|
||||
ID int `json:"id"`
|
||||
Author Author `json:"author"`
|
||||
AuthorName string `json:"author_name"`
|
||||
Text string `json:"body"`
|
||||
Title string `json:"title"`
|
||||
}
|
||||
|
||||
type CommentPost struct {
|
||||
ParentID string `json:parent_fullname`
|
||||
Body string `json:body`
|
||||
}
|
||||
|
||||
type SearchParams struct {
|
||||
Hole string
|
||||
After time.Time
|
||||
Before time.Time
|
||||
}
|
||||
|
||||
func (c *RDramaClient) UpvotePost(id int) error {
|
||||
url := fmt.Sprintf("/vote/post/%v/1", id)
|
||||
return c.makeRequest("POST", url, "", nil)
|
||||
|
||||
}
|
||||
|
||||
func (c *RDramaClient) UpvoteComment(id int) error {
|
||||
url := fmt.Sprintf("/vote/comment/%v/1", id)
|
||||
return c.makeRequest("POST", url, "", nil)
|
||||
|
||||
}
|
||||
func (c *RDramaClient) GetComments(params SearchParams) ([]Comment, error) {
|
||||
var s string
|
||||
if params.Hole != "" {
|
||||
|
@ -121,47 +71,14 @@ func (c *RDramaClient) GetComments(params SearchParams) ([]Comment, error) {
|
|||
if params.Before != nullTime {
|
||||
s += fmt.Sprintf(" before:%d", params.Before.Unix())
|
||||
}
|
||||
v := neturl.Values{}
|
||||
v := url.Values{}
|
||||
v.Set("q", s)
|
||||
url := "/search/comments?" + v.Encode()
|
||||
fmt.Printf("URL: %s\n", url)
|
||||
var comments CommentResponse
|
||||
if err := c.makeRequest("GET", url, "", &comments); err != nil {
|
||||
if err := c.makeRequest("GET", url, &comments); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return comments.Data, nil
|
||||
}
|
||||
|
||||
func (c *RDramaClient) GetPosts(params SearchParams) ([]Post, error) {
|
||||
var s string
|
||||
if params.Hole != "" {
|
||||
s += fmt.Sprintf("hole:%s", params.Hole)
|
||||
}
|
||||
nullTime := time.Time{}
|
||||
if params.After != nullTime {
|
||||
s += fmt.Sprintf(" after:%d", params.After.Unix())
|
||||
}
|
||||
if params.Before != nullTime {
|
||||
s += fmt.Sprintf(" before:%d", params.Before.Unix())
|
||||
}
|
||||
v := neturl.Values{}
|
||||
v.Set("q", s)
|
||||
url := "/search/posts?" + v.Encode()
|
||||
fmt.Printf("URL: %s\n", url)
|
||||
var posts PostResponse
|
||||
if err := c.makeRequest("GET", url, "", &posts); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return posts.Data, nil
|
||||
}
|
||||
|
||||
func (c *RDramaClient) PostComment(body string, parent string) error {
|
||||
v := neturl.Values{}
|
||||
v.Set("parent_fullname", parent)
|
||||
v.Set("body", body)
|
||||
fmt.Println(v.Encode())
|
||||
return c.makeRequest("POST", "/comment", v.Encode(), nil)
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue