package main import ( "flag" "fmt" "io" "log" "os" "os/exec" "path/filepath" "strings" "github.com/joho/godotenv" ) var Error *log.Logger var Warning *log.Logger func init() { log.SetFlags(log.Lmicroseconds | log.Lshortfile) logger := io.MultiWriter(os.Stdout) log.SetOutput(logger) Error = log.New(io.MultiWriter(os.Stderr, os.Stdout), fmt.Sprintf("%sERROR:%s ", "\033[0;101m", "\033[0m"), log.Lmicroseconds|log.Lshortfile) Warning = log.New(io.MultiWriter(os.Stdout), fmt.Sprintf("%sWarning:%s ", "\033[0;93m", "\033[0m"), log.Lmicroseconds|log.Lshortfile) } const ( steamcmdEnvKey = "STEAMCMD" steamcmdScriptPathEnvKey = "STEAMCMD_SCRIPT" appEnvKey = "APP" usernameEnvKey = "USERNAME" passwordEnvKey = "PASSWORD" ) func main() { envfile := flag.String("envfile", ".env", "") inputfile := flag.String("if", "", "") flag.Parse() args := flag.Args() if *inputfile != "" { filehandle, err := os.Open(*inputfile) if err != nil { Error.Printf("Error opening input file: %v", err) return } defer filehandle.Close() fargs, err := io.ReadAll(filehandle) if err != nil { Error.Printf("Error reading input file: %v", err) return } sargs := strings.Split(string(fargs), "\r\n") args = append(args, sargs...) } if len(args) == 0 { Error.Println("No args specified, please pass space delimited list of workshop ids for downloading") return } env, err := loadEnv(*envfile) if err != nil { Error.Printf("Error leading env file: %v", err) return } steamcmdPath, ok := env[steamcmdEnvKey] if !ok { Error.Printf("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 { Error.Printf("Error opening SteamCMD, does it exist?: %v", err) return } tempfile.Close() steamcmdScriptPath, ok := env[steamcmdScriptPathEnvKey] if !ok { steamcmdScriptPath = filepath.Join(steamcmdPath, "script") log.Printf("SteamCMD script not found in env, using '%s'", steamcmdScriptPath) log.Printf("Specify script path with '%s'", steamcmdScriptPathEnvKey) } app, ok := env[appEnvKey] if !ok { Error.Printf("App not found in env, please specify '%s'", appEnvKey) return } username, ok := env[usernameEnvKey] if !ok { username = "anonymous" log.Printf("Username not found in env, using '%s'", username) log.Printf("If you want to log in specify '%s' and '%s'", usernameEnvKey, passwordEnvKey) } password, ok := env[passwordEnvKey] if !ok { password = "" log.Printf("Password not found in env, using empty") } log.Printf("Using steamcmd at '%s'", steamcmdPath) log.Printf("As user '%s'", username) log.Printf("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 { Error.Println("Could not open steamcmd script file") return } defer scriptFileHandle.Close() _, err = scriptFileHandle.Write([]byte(strings.Join(scriptContents, "\n"))) if err != nil { Error.Println("Could not write to steamcmd script file") return } log.Printf("Wrote %d lines to script file", len(scriptContents)) steamcmdExe, _ = filepath.Abs(steamcmdExe) steamcmdScriptPath, _ = filepath.Abs(steamcmdScriptPath) log.Printf("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 { Error.Printf("SteamCMD failed with code %v", err) return } log.Printf("All done") } func loadEnv(fpath string) (map[string]string, error) { res := make(map[string]string) fpath = filepath.Clean(fpath) log.Printf("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 }