package main import ( "flag" "fmt" "io" "os" "os/exec" "path/filepath" "strings" logger "git.site.quack-lab.dev/dave/cylogger" "github.com/joho/godotenv" ) const ( steamcmdEnvKey = "STEAMCMD" steamcmdScriptPathEnvKey = "STEAMCMD_SCRIPT" appEnvKey = "APP" usernameEnvKey = "USERNAME" passwordEnvKey = "PASSWORD" ) func main() { logger.Init(logger.LevelInfo) envfile := flag.String("envfile", ".env", "") inputfile := flag.String("if", "", "") flag.Parse() args := flag.Args() if *inputfile != "" { filehandle, err := os.Open(*inputfile) if err != nil { logger.Error("Error opening input file: %v", err) return } defer filehandle.Close() fargs, err := io.ReadAll(filehandle) if err != nil { logger.Error("Error reading input file: %v", err) return } sargs := strings.Split(string(fargs), "\r\n") args = append(args, sargs...) } if len(args) == 0 { logger.Error("No args specified, please pass space delimited list of workshop ids for downloading") return } env, err := loadEnv(*envfile) if err != nil { logger.Error("Error leading env file: %v", err) return } steamcmdPath, ok := env[steamcmdEnvKey] if !ok { logger.Error("SteamCMD not found in env, please specify '%s'", steamcmdEnvKey) return } steamcmdPath = filepath.Clean(steamcmdPath) steamcmdExe := filepath.Join(steamcmdPath, "steamcmd.exe") tempfile, err := os.Open(steamcmdExe) if err != nil { logger.Error("Error opening SteamCMD, does it exist?: %v", err) return } tempfile.Close() steamcmdScriptPath, ok := env[steamcmdScriptPathEnvKey] if !ok { steamcmdScriptPath = filepath.Join(steamcmdPath, "script") logger.Info("SteamCMD script not found in env, using '%s'", steamcmdScriptPath) logger.Info("Specify script path with '%s'", steamcmdScriptPathEnvKey) } app, ok := env[appEnvKey] if !ok { logger.Error("App not found in env, please specify '%s'", appEnvKey) return } username, ok := env[usernameEnvKey] if !ok { username = "anonymous" logger.Info("Username not found in env, using '%s'", username) logger.Info("If you want to log in specify '%s' and '%s'", usernameEnvKey, passwordEnvKey) } password, ok := env[passwordEnvKey] if !ok { password = "" logger.Info("Password not found in env, using empty") } logger.Info("Using steamcmd at '%s'", steamcmdPath) logger.Info("As user '%s'", username) logger.Info("Downloading %d items for '%s'", len(args), app) scriptContents := make([]string, 0, len(args)+4) scriptContents = append(scriptContents, "@ShutdownOnFailedCommand 0") scriptContents = append(scriptContents, "@NoPromptForPassword 1") scriptContents = append(scriptContents, fmt.Sprintf("login %s %s", username, password)) for _, arg := range args { scriptContents = append(scriptContents, fmt.Sprintf("workshop_download_item %s %s", app, arg)) } scriptContents = append(scriptContents, "quit") scriptFileHandle, err := os.OpenFile(steamcmdScriptPath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0755) if err != nil { logger.Error("Could not open steamcmd script file") return } defer scriptFileHandle.Close() _, err = scriptFileHandle.Write([]byte(strings.Join(scriptContents, "\n"))) if err != nil { logger.Error("Could not write to steamcmd script file") return } logger.Info("Wrote %d lines to script file", len(scriptContents)) steamcmdExe, _ = filepath.Abs(steamcmdExe) steamcmdScriptPath, _ = filepath.Abs(steamcmdScriptPath) logger.Info("Running steamcmd at %s", steamcmdExe) cmd := exec.Command(steamcmdExe, "+runscript", steamcmdScriptPath) cmd.Dir = steamcmdPath cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr cmd.Stdin = os.Stdin err = cmd.Run() if err != nil { logger.Error("SteamCMD failed with code %v", err) return } logger.Info("All done") } func loadEnv(fpath string) (map[string]string, error) { res := make(map[string]string) fpath = filepath.Clean(fpath) logger.Info("Trying to open env file at '%s'", fpath) file, err := os.Open(fpath) if err != nil { return res, fmt.Errorf("error opening env file: %w", err) } defer file.Close() res, err = godotenv.Parse(file) if err != nil { return res, fmt.Errorf("error parsing env file: %w", err) } return res, nil }