diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..51aa16f
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,25 @@
+# syntax=docker/dockerfile:1
+FROM golang:1.20-alpine
+WORKDIR /tmp
+
+#install update system and install packages
+RUN apk update
+RUN apk upgrade --available
+
+#install yt-dlp
+RUN pip3 install yt-dlp
+
+#build nenefootbot
+WORKDIR /app
+
+COPY * ./
+
+RUN go mod download
+
+
+RUN go build -o /bloaterbot
+
+ENV NENEFOOTBOT_APITOKEN $NENEFOOTBOT_APITOKEN
+ENV NENEFOOTBOT_DEBUGMODE $NENEFOOTBOT_DEBUGMODE
+
+CMD [ "/bloaterbot" ]
\ No newline at end of file
diff --git a/bot.go b/bot.go
new file mode 100644
index 0000000..eac9813
--- /dev/null
+++ b/bot.go
@@ -0,0 +1,70 @@
+package main
+
+import (
+ tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
+ "log"
+ "regexp"
+ "strings"
+ "time"
+ "watn3y/bloaterbotv3/botIO"
+ "watn3y/bloaterbotv3/commonlogic"
+ "watn3y/bloaterbotv3/config"
+ "watn3y/bloaterbotv3/text/nhentai"
+)
+
+var shutuptime time.Time
+
+func bot() {
+ updates, bot := botIO.Authenticate()
+
+ for update := range updates {
+ if update.Message == nil {
+ continue
+ }
+
+ if update.Message.IsCommand() {
+ go commands(update, bot)
+ } else {
+ if time.Since(shutuptime).Minutes() >= 60 {
+ go textMatcher(update, bot)
+ }
+
+ }
+
+ }
+}
+
+func textMatcher(update tgbotapi.Update, bot *tgbotapi.BotAPI) {
+
+ //nhentai
+ const nhentaiRegex string = "([ \\t\\n\\r]|^)\\d{2,}([ \\t\\n\\r]|$)"
+ isNhentai, err := regexp.MatchString(nhentaiRegex, update.Message.Text)
+ if err != nil {
+ log.Panicf("Failed to compile regex for nhentai", err)
+ }
+ if isNhentai && commonlogic.ContainsInt64(config.BotConfig.Nhentai.EnabledChats, update.Message.Chat.ID) {
+ go nhentai.Nhentai(nhentaiRegex, update, bot)
+ }
+
+ //balonlyl
+ var isBalonlyl bool = false
+ for _, word := range config.BotConfig.Balonlyl.TriggerWords {
+ if strings.Contains(strings.ToLower(update.Message.Text), word) && commonlogic.ContainsInt64(config.BotConfig.Balonlyl.EnabledChats, update.Message.Chat.ID) {
+ isBalonlyl = true
+ break
+ }
+ }
+ if isBalonlyl {
+ go balonlyl(update, bot)
+ }
+
+}
+
+func commands(update tgbotapi.Update, bot *tgbotapi.BotAPI) {
+ if strings.ToLower(update.Message.Command()) == "shutup" || strings.ToLower(update.Message.Command()) == "shut" {
+ shutuptime = time.Now().UTC()
+
+ msg := tgbotapi.NewMessage(update.Message.Chat.ID, "Shutting up")
+ botIO.SendMessage(msg, bot)
+ }
+}
diff --git a/botIO/authenticate.go b/botIO/authenticate.go
new file mode 100644
index 0000000..2365468
--- /dev/null
+++ b/botIO/authenticate.go
@@ -0,0 +1,24 @@
+package botIO
+
+import (
+ tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
+ "log"
+ "watn3y/bloaterbotv3/config"
+)
+
+func Authenticate() (tgbotapi.UpdatesChannel, *tgbotapi.BotAPI) {
+
+ b, err := tgbotapi.NewBotAPI(config.BotConfig.APIToken)
+
+ if err != nil {
+ log.Panicf("Failed to connect Bot to Telegram: %v\n", err)
+ }
+
+ b.Debug = config.BotConfig.DebugMode
+
+ u := tgbotapi.NewUpdate(0)
+ u.Timeout = 60
+ log.Printf("Authorized on account %s", b.Self.UserName)
+
+ return b.GetUpdatesChan(u), b
+}
diff --git a/botIO/sending.go b/botIO/sending.go
new file mode 100644
index 0000000..ca31499
--- /dev/null
+++ b/botIO/sending.go
@@ -0,0 +1,13 @@
+package botIO
+
+import (
+ tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
+ "log"
+)
+
+func SendMessage(message tgbotapi.MessageConfig, bot *tgbotapi.BotAPI) {
+ _, err := bot.Send(message)
+ if err != nil {
+ log.Printf("Failed to send message: %v\n", err)
+ }
+}
diff --git a/commands.go b/commands.go
new file mode 100644
index 0000000..06ab7d0
--- /dev/null
+++ b/commands.go
@@ -0,0 +1 @@
+package main
diff --git a/commonlogic/commonlogic.go b/commonlogic/commonlogic.go
new file mode 100644
index 0000000..58d7b2c
--- /dev/null
+++ b/commonlogic/commonlogic.go
@@ -0,0 +1,11 @@
+package commonlogic
+
+func ContainsInt64(a []int64, b int64) bool {
+ for _, v := range a {
+ if v == b {
+ return true
+ }
+ }
+
+ return false
+}
diff --git a/config.toml.example b/config.toml.example
new file mode 100644
index 0000000..fe31832
--- /dev/null
+++ b/config.toml.example
@@ -0,0 +1,13 @@
+APIToken = "073fv3b07tvrudgbdf"
+DebugMode = true
+PrivilegedUsers = [1187583771]
+
+[Nhentai]
+APIEndpoint = "0.0.0.0"
+Domain = "https://nhentai.net"
+EnabledChats = [-1001737304244,-1001462089309,-1001616528600]
+
+[Balonlyl]
+EnabledChats = [-1001462089309]
+BalonlylAT = "@Balonlyl"
+TriggerWords = ["french","france","frankreich","french","baguette","casque bleu","casquebleu","surrender"]
\ No newline at end of file
diff --git a/config/config.go b/config/config.go
new file mode 100644
index 0000000..753ac16
--- /dev/null
+++ b/config/config.go
@@ -0,0 +1,63 @@
+package config
+
+import (
+ "fmt"
+ "github.com/BurntSushi/toml"
+ "log"
+ "os"
+ "time"
+)
+
+/*type config struct {
+ Bot struct {
+ APIToken string
+ DebugMode bool
+ PrivilegedUsers []int64
+ }
+
+ Nhentai struct {
+ EnabledChats []int64
+ EnabledUsers []int64
+ }
+
+ Balonlyl struct {
+ EnabledChats []int64
+ }
+}*/
+
+type config struct {
+ APIToken string
+ DebugMode bool
+ PrivilegedUsers []int64
+ ShutupTime time.Time
+ Nhentai struct {
+ EnabledChats []int64
+ APIEndpoint string
+ Domain string
+ }
+ Balonlyl struct {
+ EnabledChats []int64
+ BalonlylAT string
+ TriggerWords []string
+ }
+}
+
+var BotConfig config
+
+func LoadConfig() {
+ configFile, err := os.ReadFile("config.toml")
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ _, err = toml.Decode(string(configFile), &BotConfig)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ if BotConfig.DebugMode {
+ fmt.Print("Loaded config from configfile: ")
+ fmt.Printf("%+v\n", BotConfig)
+ }
+
+}
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..b6f0173
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,10 @@
+module watn3y/bloaterbotv3
+
+go 1.20
+
+require github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1
+
+require (
+ github.com/BurntSushi/toml v1.2.1 // indirect
+ gopkg.in/ini.v1 v1.67.0 // indirect
+)
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..caaf3c9
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,6 @@
+github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak=
+github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
+github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1 h1:wG8n/XJQ07TmjbITcGiUaOtXxdrINDz1b0J1w0SzqDc=
+github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1/go.mod h1:A2S0CWkNylc2phvKXWBBdD3K0iGnDBGbzRpISP2zBl8=
+gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
+gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
diff --git a/main.go b/main.go
new file mode 100644
index 0000000..2c82cb8
--- /dev/null
+++ b/main.go
@@ -0,0 +1,11 @@
+package main
+
+import (
+ "watn3y/bloaterbotv3/config"
+)
+
+func main() {
+ config.LoadConfig()
+ bot()
+
+}
diff --git a/text.go b/text.go
new file mode 100644
index 0000000..b846db2
--- /dev/null
+++ b/text.go
@@ -0,0 +1,27 @@
+package main
+
+import (
+ tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
+ "watn3y/bloaterbotv3/botIO"
+ "watn3y/bloaterbotv3/config"
+)
+
+func balonlyl(update tgbotapi.Update, bot *tgbotapi.BotAPI) {
+
+ /*balonlylLines := [4]string{
+ balonlylAT + " they're talking about you",
+ "Bitch " + balonlylAT + " they're shittalking you again",
+ "Bruh wtf " + balonlylAT + ", again",
+ balonlylAT + " look at these idiots",
+ }*/
+
+ message := tgbotapi.MessageConfig{
+ BaseChat: tgbotapi.BaseChat{ChatID: update.Message.Chat.ID, ReplyToMessageID: update.Message.MessageID},
+ ParseMode: "html",
+ DisableWebPagePreview: true,
+ //Text: balonlylLines[rand.Intn(len(balonlylLines))],
+ Text: config.BotConfig.Balonlyl.BalonlylAT,
+ }
+
+ botIO.SendMessage(message, bot)
+}
diff --git a/text/nhentai/data.go b/text/nhentai/data.go
new file mode 100644
index 0000000..3dde3d8
--- /dev/null
+++ b/text/nhentai/data.go
@@ -0,0 +1,81 @@
+package nhentai
+
+import (
+ "encoding/json"
+ "fmt"
+ "io"
+ "log"
+ "net/http"
+ "watn3y/bloaterbotv3/config"
+)
+
+func doAPIRequest(hentaiID string) (exists bool, Details nhentaiResponse) {
+
+ client := &http.Client{}
+
+ req, err := http.NewRequest("GET", config.BotConfig.Nhentai.APIEndpoint+"/gallery/"+hentaiID, nil)
+ if err != nil {
+ log.Fatalln(err)
+ }
+
+ req.Header.Set("User-Agent", "Golang_Spider_Bot/3.0")
+
+ resp, err := client.Do(req)
+ if err != nil {
+ log.Fatalln(err)
+ }
+
+ if resp.StatusCode == 404 {
+ return false, nhentaiResponse{}
+ } else if resp.StatusCode != 200 {
+ return false, nhentaiResponse{}
+ }
+
+ defer resp.Body.Close()
+ body, err := io.ReadAll(resp.Body)
+ if err != nil {
+ log.Fatalln(err)
+ }
+
+ var hentai nhentaiResponse
+ if err := json.Unmarshal(body, &hentai); err != nil { // Parse []byte to the go struct pointer
+ fmt.Println("Can not unmarshal JSON")
+ }
+
+ return true, hentai
+
+}
+
+func parseAPIResponse(rawHentai nhentaiResponse) (formattedHentai hentai) {
+ var hentai = hentai{
+ ID: rawHentai.ID,
+ Title: rawHentai.Title.Pretty,
+ UploadDate: rawHentai.UploadDate,
+ }
+
+ for _, tag := range rawHentai.Tags {
+ if tag.Type == "tag" {
+ hentai.Tags = append(hentai.Tags, struct {
+ Name string
+ URL string
+ }{Name: tag.Name, URL: tag.URL})
+
+ } /* else if tag.Type == "parody" {
+
+ } else if tag.Type == "character" {
+
+ } else if tag.Type == "language" {
+
+ } else if tag.Type == "group" {
+
+ } else if tag.Type == "artist" {
+
+ } else if tag.Type == "category" {
+
+ }*/
+
+ }
+
+ return hentai
+
+}
diff --git a/text/nhentai/nhentai.go b/text/nhentai/nhentai.go
new file mode 100644
index 0000000..55f81d4
--- /dev/null
+++ b/text/nhentai/nhentai.go
@@ -0,0 +1,41 @@
+package nhentai
+
+import (
+ tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
+ "regexp"
+ "strconv"
+ "watn3y/bloaterbotv3/botIO"
+ "watn3y/bloaterbotv3/config"
+)
+
+func Nhentai(regex string, update tgbotapi.Update, bot *tgbotapi.BotAPI) {
+
+ re := regexp.MustCompile(regex)
+ getdigit := regexp.MustCompile("\\d{2,}")
+ match := re.FindStringSubmatch(update.Message.Text)
+ hentainumber := getdigit.FindStringSubmatch(match[0])
+
+ hentaiExists, hentaiResponse := doAPIRequest(hentainumber[0])
+
+ if !hentaiExists {
+ return
+ }
+
+ hentai := parseAPIResponse(hentaiResponse)
+
+ var tags string
+ for _, tag := range hentai.Tags {
+ tags = tags + `` + tag.Name + `` + `, `
+ }
+ println(tags)
+ hentaitext := `` + `` + hentai.Title + ` ` + `` + "\n\n" + tags
+
+ message := tgbotapi.MessageConfig{
+ BaseChat: tgbotapi.BaseChat{ChatID: update.Message.Chat.ID, ReplyToMessageID: update.Message.MessageID},
+ ParseMode: "html",
+ DisableWebPagePreview: false,
+ Text: hentaitext,
+ }
+
+ botIO.SendMessage(message, bot)
+}
diff --git a/text/nhentai/types.go b/text/nhentai/types.go
new file mode 100644
index 0000000..0cabf22
--- /dev/null
+++ b/text/nhentai/types.go
@@ -0,0 +1,56 @@
+package nhentai
+
+type nhentaiResponse struct {
+ ID int `json:"id"`
+ Title struct {
+ English string `json:"english,omitempty"`
+ Chinese string `json:"chinese,omitempty"`
+ Japanese string `json:"japanese,omitempty"`
+ Pretty string `json:"pretty,omitempty"`
+ } `json:"title,omitempty"`
+ UploadDate int `json:"upload_date"`
+ Tags []struct {
+ Type string `json:"type"`
+ Name string `json:"name"`
+ URL string `json:"url"`
+ } `json:"tags"`
+}
+
+type hentai struct {
+ ID int
+ Title string
+ UploadDate int
+ /*
+ Language struct { //since there can be multiple languages I won't implement this shit
+ Name string
+ URL string
+ }
+ Artist struct {
+ Name string
+ URL string
+ }
+ Group struct {
+ Name string
+ URL string
+ }
+ Category struct {
+ Name string
+ URL string
+ }
+
+ Character struct {
+ Name string
+ URL string
+ }
+
+ Parody struct {
+ Name string
+ URL string
+ }
+ */
+
+ Tags []struct {
+ Name string
+ URL string
+ }
+}