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 + } +}