summary refs log blame commit diff stats
path: root/main.go
blob: c8ad8297b2615e881af3cb9c5055d90c9437ca63 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16















                                                                           
        
                       

              
                   
             
                   
                  
                 
                 



              
                             





                          


                  

 
             
                                    
 

                         
 







                                            


                                        

                                                                                    
 


                                                                   

                                                                                                   
                                                                                                        
                                                                               
                                                                                                              
                                                                            

                    

                                                    

         


                                                  
         
 





                                                    
 




                                              
         
                    

 














                                                                  
         
 

                           
 


                                               














































                                                                 
                           
 
 



                                               

















                                                           
                                                                 
                       
                              


                             










                                                                         



                                     
                              




                                                
                              



                                                       












                                                                                   
 








                                                                               

         
                                                                     
                       
                              
         


                               
                              


                              



                                                         
 


                                        
                       
                                                         


                          


                                                             
















                                                        
// Copyright (c) 2020, Andinus <andinus@inventati.org>

// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.

// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"math/rand"
	"net/http"
	"os/exec"
	"strconv"
	"time"
)

var (
	timeout time.Duration

	apodAPI     string
	apodAPIKey  string
	bpodAPI     string
	bpodNum     int
	unsplashAPI string

	width  int
	height int
)

func main() {
	rand.Seed(time.Now().Unix())

	var (
		err error

		imgPath string
		mode    string
		src     string
		srcArr  []string = []string{
			"apod",
			"bpod",
			"unsplash",
		}
	)

	// Parse flags passed to program
	flag.StringVar(&src, "src", "random", "Source for the image")
	flag.StringVar(&mode, "mode", "random", "Daily, Weekly or Random wallpaper")

	flag.IntVar(&width, "width", 1920, "Width of the image")
	flag.IntVar(&height, "height", 1080, "Height of the image")

	flag.StringVar(&apodAPI, "apod-api", "https://api.nasa.gov/planetary/apod", "APOD API URL")
	flag.StringVar(&apodAPIKey, "apod-api-key", "DEMO_KEY", "APOD API Key")
	flag.StringVar(&bpodAPI, "bpod-api", "https://www.bing.com/HPImageArchive.aspx", "BPOD API URL")
	flag.IntVar(&bpodNum, "bpod-num", 16, "BPOD Number of images to fetch")
	flag.StringVar(&unsplashAPI, "unsplash-api", "https://source.unsplash.com", "Unsplash Source API URL")
	flag.DurationVar(&timeout, "timeout", 16, "Timeout for http client")
	flag.Parse()

	if src == "random" {
		src = srcArr[rand.Intn(len(srcArr))]
	}

	// Check if the source is known
	if !contains(srcArr, src) {
		log.Fatal("Error: Unknown Source")
	}

	imgPath, err = parseSrcAndGetPath(src, mode)
	errChk(err)

	err = setWall(imgPath)
	errChk(err)
}

func contains(arr []string, str string) bool {
	for _, i := range arr {
		if i == str {
			return true
		}
	}
	return false
}

// Gets image path from src
func parseSrcAndGetPath(src string, mode string) (string, error) {
	var err error
	var imgPath string

	switch src {
	case "apod":
		fmt.Println("Astronomy Picture of the Day")
		imgPath, err = getPathAPOD(mode)
	case "bpod":
		fmt.Println("Bing Photo of the Day")
		imgPath, err = getPathBPOD(mode)
	case "unsplash":
		fmt.Println("Unsplash Source")
		imgPath, err = getPathUnsplash(mode)
	}

	return imgPath, err
}

func getPathAPOD(mode string) (string, error) {
	var err error
	var imgPath string

	switch mode {
	case "daily", "random":
		break
	default:
		return "", fmt.Errorf("Error: Unknown Mode")
	}

	type apodRes struct {
		Copyright      string `json:"copyright"`
		Date           string `json:"string"`
		Explanation    string `json:"explanation"`
		HDURL          string `json:"hdurl"`
		MediaType      string `json:"media_type"`
		ServiceVersion string `json:"service_version"`
		Title          string `json:"title"`
		URL            string `json:"url"`
	}

	apodNow := apodRes{}

	req, err := http.NewRequest(http.MethodGet, apodAPI, nil)
	if err != nil {
		return "", err
	}
	q := req.URL.Query()
	q.Add("api_key", apodAPIKey)
	req.URL.RawQuery = q.Encode()

	res, err := getRes(req)
	if err != nil {
		fmt.Printf("Error: GET %s\n", apodAPI)
		return "", err
	}
	defer res.Body.Close()

	apiBody, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return "", err
	}

	err = json.Unmarshal([]byte(apiBody), &apodNow)
	if err != nil {
		return "", err
	}

	imgPath = apodNow.HDURL
	return imgPath, err
}

func getPathBPOD(mode string) (string, error) {
	var err error
	var imgPath string

	type Images struct {
		StartDate     string `json:"startdate"`
		FullStartDate string `json:"fullstartdate"`
		EndDate       string `json:"enddate"`
		URL           string `json:"url"`
		URLBase       string `json:"urlbase"`
		Copyright     string `json:"copyright"`
		CopyrightLink string `json:"copyrightlink"`
		Title         string `json:"title"`
		Hsh           string `json:"hsh"`
	}

	type bpodRes struct {
		Image []Images `json:"images"`
	}

	bpodNow := bpodRes{}

	req, err := http.NewRequest(http.MethodGet, bpodAPI, nil)
	if err != nil {
		return "", err
	}
	q := req.URL.Query()
	q.Add("format", "js")

	switch mode {
	case "daily":
		q.Add("n", "1")
	case "random":
		// Fetches 16 images (only info) & chooses a random image
		q.Add("n", strconv.Itoa(bpodNum))
	default:
		return "", fmt.Errorf("Error: Unknown Mode")
	}

	req.URL.RawQuery = q.Encode()

	res, err := getRes(req)
	if err != nil {
		return "", err
	}
	defer res.Body.Close()

	apiBody, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return "", err
	}

	err = json.Unmarshal([]byte(apiBody), &bpodNow)
	if err != nil {
		return "", err
	}

	// Choose a random image
	var i int = rand.Intn(len(bpodNow.Image))
	imgPath = fmt.Sprintf("%s%s", "https://www.bing.com", bpodNow.Image[i].URL)

	return imgPath, err
}

func getPathUnsplash(mode string) (string, error) {
	var err error
	var imgPath string

	switch mode {
	case "daily", "weekly":
		unsplashAPI = fmt.Sprintf("%s/%s",
			unsplashAPI, mode)
	case "random":
		unsplashAPI = fmt.Sprintf("%s/%sx%s",
			unsplashAPI, strconv.Itoa(width), strconv.Itoa(height))
	default:
		return "", fmt.Errorf("Error: Unknown Mode")
	}

	req, err := http.NewRequest(http.MethodGet, unsplashAPI, nil)
	if err != nil {
		return "", err
	}

	res, err := getRes(req)
	if err != nil {
		return "", err
	}
	defer res.Body.Close()

	// Unsplash Source API will redirect to the image
	imgPath = res.Request.URL.String()
	return imgPath, err
}

// Calls feh to set the wallpaper
func setWall(imgPath string) error {
	feh, err := exec.LookPath("feh")
	if err != nil {
		fmt.Println("Error: feh is not in $PATH")
		return err
	}

	fmt.Printf("Path to set as Wallpaper: %s\n", imgPath)

	err = exec.Command(feh, "--bg-fill", imgPath).Run()
	return err
}

func getRes(req *http.Request) (*http.Response, error) {
	client := http.Client{
		Timeout: time.Second * timeout,
	}
	res, err := client.Do(req)

	return res, err
}

func errChk(err error) {
	if err != nil {
		log.Fatal(err)
	}
}