package main import ( "fmt" "net" "syscall" "strings" "strconv" "os" "os/exec" "io/ioutil" "time" "github.com/BurntSushi/toml" ) type Config struct { Delay int Separator string IP IPConfig Mounts MountConfig Music MusicConfig Clock ClockConfig } type IPConfig struct { Label string Interfaces []string IPv4Only bool `toml:"ipv4only"` } type MountConfig struct { Label string MountPoints []string `toml:"mountpoints"` } type MusicConfig struct { LabelPlaying string `toml:"labelplaying"` LabelPaused string `toml:"labelpaused"` LabelStopped string `toml:"labelstopped"` } type ClockConfig struct { Label string Format string } func diskSizes(mounts []string) string { var b strings.Builder var statfs syscall.Statfs_t const div = float64(1024 * 1024 * 1024) const unit = "G" sep := "" for _, mount := range mounts { b.WriteString(sep) err := syscall.Statfs(mount, &statfs) if err != nil { panic(err) } availBytes := float64(statfs.Bavail * uint64(statfs.Bsize)) avail := strconv.FormatFloat(availBytes / div, 'f', 2, 64) b.WriteString(fmt.Sprintf("%v : %v %v", mount, avail, unit)) sep = " " } return b.String() } func ips(interfaces []string, IPv4Only bool) string { var b strings.Builder sep := "" for _, interfaceName := range interfaces { b.WriteString(sep) b.WriteString(interfaceName) b.WriteString(": ") if len(interfaces) > 1 { b.WriteString(" [") } b.WriteString(ip(interfaceName, IPv4Only)) if len(interfaces) > 1 { b.WriteString(" ]") } sep = " " } return b.String() } func ip(interfaceName string, IPv4Only bool) string { var b strings.Builder sep := "" in, err := net.InterfaceByName(interfaceName) if err != nil { panic(err) } addrs, err := in.Addrs() if err != nil { panic(err) } for _, addr := range addrs { var ip net.IP switch v := addr.(type) { case *net.IPAddr: ip = v.IP case *net.IPNet: ip = v.IP default: } if IPv4Only { if ip.To4() != nil { b.WriteString(ip.String()) b.WriteString(sep) sep = " " } } else { b.WriteString(sep) b.WriteString(ip.String()) sep = " " } } return b.String() } func clock(format string) string { t := time.Now() return t.Format(format) } func nowPlayingMPD() string { cmd := exec.Command("mpc", "current") out, err := cmd.Output() if err != nil { panic(err) } sOut := string(out) sOut = strings.ReplaceAll(sOut, "\n", "") return sOut } // Returns 0 if playing, 1 if paused and 2 if stopped func statusMPD() int { cmd := exec.Command("mpc", "status") out, err := cmd.Output() if err != nil { panic(err) } sOut := string(out) if strings.Contains(sOut, "playing") { return 0 } else if strings.Contains(sOut, "paused") { return 1 } else { return 2 } } func main() { var configPath = "/etc/statusbar.conf" var content []byte var err error if _, err := os.Stat(configPath); err != nil { content, err = ioutil.ReadAll(os.Stdin) } else { content, err = ioutil.ReadFile(configPath) } if err != nil { panic(err) } var config Config _, err = toml.Decode(string(content), &config) if err != nil { panic(err) } for true { var b strings.Builder switch statusMPD() { case 0: b.WriteString(config.Music.LabelPlaying) case 1: b.WriteString(config.Music.LabelPaused) case 2: b.WriteString(config.Music.LabelStopped) default: b.WriteString("Unknown MPD status") } b.WriteString(nowPlayingMPD()) b.WriteString(config.Separator) b.WriteString(config.IP.Label) b.WriteString("[ ") b.WriteString(ips(config.IP.Interfaces, config.IP.IPv4Only)) b.WriteString(" ]") b.WriteString(config.Separator) b.WriteString(config.Mounts.Label) b.WriteString("[ ") b.WriteString(diskSizes(config.Mounts.MountPoints)) b.WriteString(" ]") b.WriteString(config.Separator) b.WriteString(config.Clock.Label) b.WriteString(clock(config.Clock.Format)) fmt.Println(b.String()) time.Sleep(time.Duration(config.Delay) * time.Second) } }