package main import ( "encoding/json" "flag" "fmt" "io/ioutil" "log" "math" "os" "os/exec" "path" "path/filepath" "strconv" "strings" "time" ) type sunsetConfig struct { Files []sunsetImage `json:"files"` } type sunsetImage struct { File string `json:"file"` Time string `json:"time"` } func loadSunsetConfig(filepath string) sunsetConfig { data, err := ioutil.ReadFile(filepath) var result sunsetConfig err = json.Unmarshal(data, &result) if err != nil { log.Fatal("Failed to load file: ", err.Error()) } return result } func currentIndex(config sunsetConfig) int { currentTime := getCurrentTime() var min int = 2401 var minIndex int = -1 for i := 0; i < len(config.Files); i++ { element := getTimeSimple(config.Files[i].Time) diff := currentTime - element if diff < 0 { diff = 2400 - (diff * -1) } if diff < min { min = diff minIndex = i } } return minIndex } func nextIndex(config sunsetConfig) int { currentTime := getCurrentTime() var min int = 2401 var minIndex int = -1 for i := 0; i < len(config.Files); i++ { element := getTimeSimple(config.Files[i].Time) diff := element - currentTime if diff < 0 { diff = 2400 - (diff * -1) } if diff < min { min = diff minIndex = i } } return minIndex } func getCurrentTime() int { now := time.Now() hr := now.Hour() min := now.Minute() return hr*100 + min } func getTimeSimple(timeString string) int { hr, min := getTime(timeString) return hr*100 + min } func getNextTime(config sunsetConfig) string { index := nextIndex(config) return config.Files[index].Time } func getTime(timeString string) (int, int) { splits := strings.Split(timeString, ":") hr, _ := strconv.ParseInt(splits[0], 10, 32) min, _ := strconv.ParseInt(splits[1], 10, 32) // res, err := time.Parse("15:04", fmt.Sprintf("%02d:%02d", hr, min)) // if err != nil { // log.Fatal(err) // } return int(hr), int(min) } func getNextWait(config sunsetConfig) time.Duration { index := nextIndex(config) now := time.Now() nextHr, nextMin := getTime(config.Files[index].Time) // Today at the time nextTime := time.Date(now.Year(), now.Month(), now.Day(), nextHr, nextMin, 0, 0, now.Location()) until := nextTime.Sub(now) if math.Floor(until.Minutes()) > 0 { return until } // Next day the the time nextTime = nextTime.AddDate(0, 0, 1) return nextTime.Sub(now) } func currentImage(configPath string, config sunsetConfig) string { index := currentIndex(config) absFile, err := filepath.Abs(path.Join(path.Dir(configPath), config.Files[index].File)) if err != nil { log.Panic(err) } return absFile } func block(configPath string, config sunsetConfig, command string) { image := currentImage(configPath, config) go runCommand(command, image) for { until := getNextWait(config) timer := time.NewTimer(until) <-timer.C log.Printf("Running command: %s\n", command) image := currentImage(configPath, config) go runCommand(command, image) } } func runCommand(command, image string) { cmd := exec.Command(command, image) err := cmd.Run() if err != nil { log.Printf("Command %s returned a non 0 code", command) } } func main() { printNextTime := flag.Bool("next", false, "Print the time to the next change") printNextWait := flag.Bool("wait", false, "Print the time to wait for the next change") blockFlag := flag.Bool("block", false, "Block and call the provided command when the background changes") blockCommand := flag.String("command", "", "Specify a command to run when the background changed") configFile := flag.String("file", "./sunset.json", "Specify the file to load") flag.Parse() conf := loadSunsetConfig(*configFile) if *printNextTime { fmt.Printf("%s", getNextTime(conf)) } else if *printNextWait { unitl := getNextWait(conf) fmt.Printf("%s", unitl) } else if *blockFlag { if *blockCommand == "" { fmt.Println("Must provide a command.") os.Exit(1) } block(*configFile, conf, *blockCommand) } else { fmt.Printf("%s", currentImage(*configFile, conf)) } }