init DiscordGo (2)

This commit is contained in:
Penguin-71630
2025-12-07 17:22:42 +08:00
parent 5c32bb11c9
commit 0fff1ed54c
3 changed files with 363 additions and 0 deletions

218
api/client.go Normal file
View File

@@ -0,0 +1,218 @@
package api
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"time"
)
type Client struct {
baseURL string
httpClient *http.Client
token string
}
type Image struct {
ID string `json:"id"`
UploadedUserID string `json:"uploaded_user_id"`
UploadedAt time.Time `json:"uploaded_at"`
Aliases []string `json:"aliases"`
URL string `json:"url"`
}
type ImagesResponse struct {
Images []Image `json:"images"`
}
type AliasesResponse struct {
Aliases []string `json:"aliases"`
}
func NewClient(baseURL string) *Client {
return &Client{
baseURL: baseURL,
httpClient: &http.Client{
Timeout: 30 * time.Second,
},
}
}
func (c *Client) SetToken(token string) {
c.token = token
}
func (c *Client) GetImages(search string, limit, page int) (*ImagesResponse, error) {
url := fmt.Sprintf("%s/api/images?search=%s&limit=%d&page=%d", c.baseURL, search, limit, page)
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return nil, err
}
if c.token != "" {
req.Header.Set("Authorization", "Bearer "+c.token)
}
resp, err := c.httpClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("API returned status %d", resp.StatusCode)
}
var result ImagesResponse
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
return nil, err
}
return &result, nil
}
func (c *Client) GetImage(id string) (*Image, error) {
url := fmt.Sprintf("%s/api/images/%s", c.baseURL, id)
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return nil, err
}
if c.token != "" {
req.Header.Set("Authorization", "Bearer "+c.token)
}
resp, err := c.httpClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("API returned status %d", resp.StatusCode)
}
var image Image
if err := json.NewDecoder(resp.Body).Decode(&image); err != nil {
return nil, err
}
return &image, nil
}
func (c *Client) GetAliases() (*AliasesResponse, error) {
url := fmt.Sprintf("%s/api/aliases", c.baseURL)
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return nil, err
}
if c.token != "" {
req.Header.Set("Authorization", "Bearer "+c.token)
}
resp, err := c.httpClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("API returned status %d", resp.StatusCode)
}
var result AliasesResponse
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
return nil, err
}
return &result, nil
}
func (c *Client) UploadImage(imageData []byte, aliases []string) (*Image, error) {
// TODO: Implement multipart form upload
return nil, fmt.Errorf("not implemented")
}
func (c *Client) DeleteImage(id string) error {
url := fmt.Sprintf("%s/api/images/%s", c.baseURL, id)
req, err := http.NewRequest("DELETE", url, nil)
if err != nil {
return err
}
if c.token != "" {
req.Header.Set("Authorization", "Bearer "+c.token)
}
resp, err := c.httpClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusNoContent {
return fmt.Errorf("API returned status %d", resp.StatusCode)
}
return nil
}
func (c *Client) AddAlias(imageID, alias string) (*Image, error) {
url := fmt.Sprintf("%s/api/images/%s/aliases", c.baseURL, imageID)
body := map[string]string{"alias": alias}
jsonBody, err := json.Marshal(body)
if err != nil {
return nil, err
}
req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonBody))
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/json")
if c.token != "" {
req.Header.Set("Authorization", "Bearer "+c.token)
}
resp, err := c.httpClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("API returned status %d", resp.StatusCode)
}
var image Image
if err := json.NewDecoder(resp.Body).Decode(&image); err != nil {
return nil, err
}
return &image, nil
}
func (c *Client) GetImageFile(id string) ([]byte, error) {
url := fmt.Sprintf("%s/api/images/%s/file", c.baseURL, id)
resp, err := c.httpClient.Get(url)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("API returned status %d", resp.StatusCode)
}
return io.ReadAll(resp.Body)
}

128
bot/commands.go Normal file
View File

@@ -0,0 +1,128 @@
package bot
import (
"fmt"
"strings"
"github.com/bwmarrin/discordgo"
)
func (b *Bot) onMessageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
// Ignore messages from the bot itself
if m.Author.ID == s.State.User.ID {
return
}
// Check if message starts with prefix
if !strings.HasPrefix(m.Content, b.config.Prefix) {
return
}
// Parse command
content := strings.TrimPrefix(m.Content, b.config.Prefix)
args := strings.Fields(content)
if len(args) == 0 {
return
}
command := strings.ToLower(args[0])
commandArgs := args[1:]
// Route commands
switch command {
case "help":
b.handleHelp(s, m)
case "meme":
b.handleMeme(s, m, commandArgs)
case "upload":
b.handleUpload(s, m, commandArgs)
case "search":
b.handleSearch(s, m, commandArgs)
case "aliases":
b.handleAliases(s, m)
case "ping":
b.handlePing(s, m)
default:
s.ChannelMessageSend(m.ChannelID, fmt.Sprintf("Unknown command: `%s`. Use `%shelp` for available commands.", command, b.config.Prefix))
}
}
func (b *Bot) handleHelp(s *discordgo.Session, m *discordgo.MessageCreate) {
embed := &discordgo.MessageEmbed{
Title: "🤖 MemeBot Commands",
Description: "Available commands for the MemeBot",
Color: 0x00ff00,
Fields: []*discordgo.MessageEmbedField{
{
Name: fmt.Sprintf("%shelp", b.config.Prefix),
Value: "Show this help message",
Inline: false,
},
{
Name: fmt.Sprintf("%smeme <alias>", b.config.Prefix),
Value: "Get a meme by alias",
Inline: false,
},
{
Name: fmt.Sprintf("%ssearch <keyword>", b.config.Prefix),
Value: "Search for memes by keyword",
Inline: false,
},
{
Name: fmt.Sprintf("%supload <url> <aliases...>", b.config.Prefix),
Value: "Upload a meme with aliases",
Inline: false,
},
{
Name: fmt.Sprintf("%saliases", b.config.Prefix),
Value: "List all available aliases",
Inline: false,
},
{
Name: fmt.Sprintf("%sping", b.config.Prefix),
Value: "Check if bot is responsive",
Inline: false,
},
},
}
s.ChannelMessageSendEmbed(m.ChannelID, embed)
}
func (b *Bot) handleMeme(s *discordgo.Session, m *discordgo.MessageCreate, args []string) {
if len(args) == 0 {
s.ChannelMessageSend(m.ChannelID, fmt.Sprintf("Usage: `%smeme <alias>`", b.config.Prefix))
return
}
alias := strings.Join(args, " ")
// TODO: Implement API call to get meme by alias
s.ChannelMessageSend(m.ChannelID, fmt.Sprintf("🔍 Searching for meme with alias: `%s`\n(API integration pending)", alias))
}
func (b *Bot) handleSearch(s *discordgo.Session, m *discordgo.MessageCreate, args []string) {
if len(args) == 0 {
s.ChannelMessageSend(m.ChannelID, fmt.Sprintf("Usage: `%ssearch <keyword>`", b.config.Prefix))
return
}
keyword := strings.Join(args, " ")
// TODO: Implement API call to search memes
s.ChannelMessageSend(m.ChannelID, fmt.Sprintf("🔍 Searching for: `%s`\n(API integration pending)", keyword))
}
func (b *Bot) handleUpload(s *discordgo.Session, m *discordgo.MessageCreate, args []string) {
// TODO: Implement meme upload functionality
s.ChannelMessageSend(m.ChannelID, "📤 Upload functionality coming soon!\n(API integration pending)")
}
func (b *Bot) handleAliases(s *discordgo.Session, m *discordgo.MessageCreate) {
// TODO: Implement API call to get all aliases
s.ChannelMessageSend(m.ChannelID, "📋 Fetching all aliases...\n(API integration pending)")
}
func (b *Bot) handlePing(s *discordgo.Session, m *discordgo.MessageCreate) {
s.ChannelMessageSend(m.ChannelID, "🏓 Pong! Bot is online.")
}

17
go.sum Normal file
View File

@@ -0,0 +1,17 @@
github.com/bwmarrin/discordgo v0.27.1 h1:ib9AIc/dom1E/fSIulrBwnez0CToJE113ZGt4HoliGY=
github.com/bwmarrin/discordgo v0.27.1/go.mod h1:NJZpH+1AfhIcyQsPeuBKsUtYrRnjkyu0kIVMCHkZtRY=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=