diff options
| author | Bobby <[email protected]> | 2025-03-27 10:53:55 +0530 |
|---|---|---|
| committer | Bobby <[email protected]> | 2025-03-27 10:53:55 +0530 |
| commit | c9067d21d4fd93f7469b92e198b6a2fffe57f699 (patch) | |
| tree | f603a218c36bb74431bf11360487971747d877aa | |
| download | ai-c9067d21d4fd93f7469b92e198b6a2fffe57f699.tar.xz ai-c9067d21d4fd93f7469b92e198b6a2fffe57f699.zip | |
Initialised Bare Bones
| -rw-r--r-- | .env.example | 6 | ||||
| -rw-r--r-- | .gitignore | 32 | ||||
| -rw-r--r-- | Makefile | 45 | ||||
| -rw-r--r-- | ai/main.go | 12 | ||||
| -rw-r--r-- | config/config.go | 90 | ||||
| -rw-r--r-- | go.mod | 5 | ||||
| -rw-r--r-- | go.sum | 2 | ||||
| -rw-r--r-- | types/bot.go | 19 | ||||
| -rw-r--r-- | types/logger.go | 34 | ||||
| -rw-r--r-- | utils/logger/logger.go | 99 |
10 files changed, 344 insertions, 0 deletions
diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..5e9f24c --- /dev/null +++ b/.env.example @@ -0,0 +1,6 @@ +DISCORD_TOKEN= +YOUTUBE_API_KEY= +SPOTIFY_CLIENT_ID= +SPOTIFY_CLIENT_SECRET= +ACTIVITY= # Activity Type is of type int, 1: Playing, 2: Listening, 3: Watching, 4: Streaming +ACTIVITY_MESSAGE=
\ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..91aead3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,32 @@ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ + +# Go workspace file +go.work + +# OS Specific +.DS_Store +Thumbs.db + +# IDE +.idea +.vscode + +# Build files +bin/ + +# Environment variables +.env diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..8417dbf --- /dev/null +++ b/Makefile @@ -0,0 +1,45 @@ +BINARY_NAME=ai +BUILD_PATH=bin/$(BINARY_NAME) +MAIN_PATH=$(BINARY_NAME)/main.go +ENV_PATH=.env + +.PHONY: setup clean build run dev all + +define ensure_setup + @if [ ! -f $(ENV_PATH) ]; then \ + echo "Running setup first..."; \ + $(MAKE) -s setup; \ + fi +endef + +setup: + @echo "Setting up environment..." + @go mod download + @if [ ! -f $(ENV_PATH) ]; then cp .env.example $(ENV_PATH); fi + @echo "Environment setup complete." + +clean: + @echo "Cleaning up..." + @rm -rf bin + @echo "Cleanup complete." + +build: + $(call ensure_setup) + @echo "Building..." + @go build -o $(BUILD_PATH) $(MAIN_PATH) || true + @echo "Build complete." + +run: + $(call ensure_setup) + @if [ ! -f $(BUILD_PATH) ]; then echo "Binary not found. Building binary..."; $(MAKE) -s build; fi + @echo "Running..." + @$(BUILD_PATH) || true + +dev: + $(call ensure_setup) + @echo "Running in development mode..." + @go run $(MAIN_PATH) || true + +all: setup clean build run + +.SILENT:
\ No newline at end of file diff --git a/ai/main.go b/ai/main.go new file mode 100644 index 0000000..433dab2 --- /dev/null +++ b/ai/main.go @@ -0,0 +1,12 @@ +package main + +import ( + "ai/config" + "ai/types" + "ai/utils/logger" + "fmt" +) + +func main() { + logger.Log(fmt.Sprintf("Bot Started. Config: %+v", config.Config), types.LogOptions{}) +} diff --git a/config/config.go b/config/config.go new file mode 100644 index 0000000..e9f08b5 --- /dev/null +++ b/config/config.go @@ -0,0 +1,90 @@ +package config + +import ( + "ai/types" + "ai/utils/logger" + "os" + "strconv" + "strings" + + "github.com/joho/godotenv" +) + +var Config *types.BotConfig + +func init() { + logPrefix := "Config" + logOptions := types.LogOptions{ + Timestamp: true, + Prefix: logPrefix, + Level: types.Error, + Fatal: true, + } + + if err := godotenv.Load(); err != nil { + logger.Log("Failed to load environment variables", logOptions) + } + + Config = &types.BotConfig{ + DiscordToken: getEnv("DISCORD_TOKEN"), + SpotifyClientId: getEnv("SPOTIFY_CLIENT_ID"), + SpotifyClientSecret: getEnv("SPOTIFY_CLIENT_SECRET"), + YoutubeAPIKey: getEnv("YOUTUBE_API_KEY"), + Activity: types.ActivityType(getIntEnv("ACTIVITY")), + ActivityMessage: getEnv("ACTIVITY_MESSAGE"), + } + + if Config.DiscordToken == "" { + logger.Log("Unable to read Discord token. environment variable DISCORD_TOKEN is required", logOptions) + } + + if Config.SpotifyClientId == "" { + logger.Log("Unable to read Spotify client ID. environment variable SPOTIFY_CLIENT_ID is required", logOptions) + } + + if Config.SpotifyClientSecret == "" { + logger.Log("Unable to read Spotify client secret. environment variable SPOTIFY_CLIENT_SECRET is required", logOptions) + } + + if Config.YoutubeAPIKey == "" { + logger.Log("Unable to read YouTube API key. environment variable YOUTUBE_API_KEY is required", logOptions) + } + + if Config.Activity == 0 { + logOptions.Level = types.Warn + logOptions.Fatal = false + logger.Log("Activity message is empty or not set. Defaulting to PLAYING", logOptions) + Config.Activity = types.PLAYING + } + + if Config.ActivityMessage == "" { + logOptions.Level = types.Warn + logOptions.Fatal = false + logger.Log("Activity message is empty or not set. Defaulting to empty string", logOptions) + Config.ActivityMessage = "" + } + + logOptions.Level = types.Success + logOptions.Fatal = false + logger.Log("Config loaded successfully", logOptions) +} + +func getEnv(key string) string { + value, exists := os.LookupEnv(key) + if !exists { + return "" + } + return strings.TrimSpace(value) +} + +func getIntEnv(key string) int { + value := getEnv(key) + if value == "" { + return 0 + } + i, err := strconv.Atoi(value) + if err != nil { + return 0 + } + return i +} @@ -0,0 +1,5 @@ +module ai + +go 1.24.1 + +require github.com/joho/godotenv v1.5.1 @@ -0,0 +1,2 @@ +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= diff --git a/types/bot.go b/types/bot.go new file mode 100644 index 0000000..417aecc --- /dev/null +++ b/types/bot.go @@ -0,0 +1,19 @@ +package types + +type ActivityType int + +const ( + PLAYING ActivityType = iota + LISTENING + WATCHING + STREAMING +) + +type BotConfig struct { + DiscordToken string + SpotifyClientId string + SpotifyClientSecret string + YoutubeAPIKey string + Activity ActivityType + ActivityMessage string +} diff --git a/types/logger.go b/types/logger.go new file mode 100644 index 0000000..a913312 --- /dev/null +++ b/types/logger.go @@ -0,0 +1,34 @@ +package types + +type LogLevel string + +const ( + Debug LogLevel = "debug" + Info LogLevel = "info" + Warn LogLevel = "warn" + Error LogLevel = "error" + Success LogLevel = "success" + + Reset = "\033[0m" + Cyan = "\033[36m" + Gray = "\033[90m" + + LevelColorInfo = "\033[34mINFO \033[0m" + LevelColorWarn = "\033[33mWARN \033[0m" + LevelColorError = "\033[31mERROR \033[0m" + LevelColorDebug = "\033[35mDEBUG \033[0m" + LevelColorSuccess = "\033[32mSUCCESS\033[0m" + + MessageColorInfo = "\033[97m" + MessageColorWarn = "\033[33m" + MessageColorError = "\033[31m" + MessageColorDebug = "\033[90m" + MessageColorSuccess = "\033[32m" +) + +type LogOptions struct { + Timestamp bool + Prefix string + Level LogLevel + Fatal bool +} diff --git a/utils/logger/logger.go b/utils/logger/logger.go new file mode 100644 index 0000000..87e7772 --- /dev/null +++ b/utils/logger/logger.go @@ -0,0 +1,99 @@ +package logger + +import ( + "fmt" + "os" + "strings" + "time" + + "ai/types" +) + +func getTimestamp() string { + return time.Now().Format(time.RFC3339) +} + +func getLevelColor(level types.LogLevel) string { + switch level { + case types.Info: + return types.LevelColorInfo + case types.Warn: + return types.LevelColorWarn + case types.Error: + return types.LevelColorError + case types.Debug: + return types.LevelColorDebug + case types.Success: + return types.LevelColorSuccess + default: + return types.LevelColorInfo + } +} + +func getMessageColor(level types.LogLevel) string { + switch level { + case types.Info: + return types.MessageColorInfo + case types.Warn: + return types.MessageColorWarn + case types.Error: + return types.MessageColorError + case types.Debug: + return types.MessageColorDebug + case types.Success: + return types.MessageColorSuccess + default: + return types.MessageColorInfo + } +} + +func Log(message interface{}, options types.LogOptions) { + var builder strings.Builder + + if options.Level == "" { + options.Level = types.Info + } + + if options.Timestamp { + builder.WriteString(types.Gray) + builder.WriteString(getTimestamp()) + builder.WriteString(types.Reset) + builder.WriteString(" ") + } + + builder.WriteString(getLevelColor(options.Level)) + builder.WriteString(" ") + + if options.Prefix != "" { + builder.WriteString(types.Cyan) + builder.WriteString("[") + builder.WriteString(options.Prefix) + builder.WriteString("]") + builder.WriteString(types.Reset) + builder.WriteString(" ") + } + + builder.WriteString(getMessageColor(options.Level)) + + switch msg := message.(type) { + case error: + builder.WriteString(msg.Error()) + case string: + builder.WriteString(msg) + default: + builder.WriteString(fmt.Sprintf("%v", msg)) + } + + builder.WriteString(types.Reset) + builder.WriteString("\n") + + if options.Level == types.Error || options.Level == types.Warn { + os.Stderr.WriteString(builder.String()) + } else { + os.Stdout.WriteString(builder.String()) + } + + if options.Fatal { + os.Exit(1) + } +} |
