summary refs log tree commit diff stats
path: root/main.go
Commit message (Expand)AuthorAgeFilesLines
* comments editedBen Morrison2019-05-281-1/+1
* removed extraneous commentsBen Morrison2019-05-271-4/+2
* configuration init changesBen Morrison2019-05-231-3/+3
* tuning query handlingBen Morrison2019-05-221-1/+16
* runtime bugs related to api outputBen Morrison2019-05-211-0/+1
* rename closeLog channelBen Morrison2019-05-211-1/+1
* added cache update / db push intervals to conf;Ben Morrison2019-05-211-3/+3
* endpoint query function addedBen Morrison2019-05-201-7/+9
* middleware func to attach remote ip to contextBen Morrison2019-05-201-1/+7
* allowing underscore and hyphen in users/tagsBen Morrison2019-05-141-2/+2
* serving css virtually instead of directlyBen Morrison2019-05-131-0/+3
* redundant path removed. comments added.Ben Morrison2019-05-131-3/+5
* watching for ^C. added comments.Ben Morrison2019-05-131-2/+12
* reorganized handlers. StrictSlash(true). handling POST /api/plain/users for n...Ben Morrison2019-05-121-9/+25
* added stdoutLogging bool and related configurationBen Morrison2019-05-121-1/+0
* commented someBen Morrison2019-05-121-1/+9
* config fleshed out; using viper+pflagBen Morrison2019-05-121-3/+4
* query vars to endpoint in routingBen Morrison2019-05-111-1/+3
* more graceful routing of http requestsBen Morrison2019-05-111-8/+23
* skeleton handlers respondingBen Morrison2019-05-111-6/+8
* stubbed out handlersBen Morrison2019-05-111-2/+8
* gzipped responsesBen Morrison2019-05-111-2/+6
* reorgBen Morrison2019-05-111-1/+1
* change port for unprivileged bindsBen Morrison2019-05-101-1/+1
* building the skeletonBen Morrison2019-05-101-0/+14
f0 } /* Literal.String */ .highlight .na { color: #336699 } /* Name.Attribute */ .highlight .nb { color: #003388 } /* Name.Builtin */ .highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */ .highlight .no { color: #003366; font-weight: bold } /* Name.Constant */ .highlight .nd { color: #555555 } /* Name.Decorator */ .highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
// 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"
	"net/http"
	"os/exec"
	"time"
)

var (
	err     error
	timeout time.Duration
)

func main() {
	var (
		imgPath string

		apod       bool
		apodAPI    string
		apodAPIKey string

		bpod    bool
		bpodAPI string
	)

	// Parse flags passed to program
	flag.StringVar(&imgPath, "img-path", "", "Image to set as wallpaper")

	flag.BoolVar(&apod, "apod", false, "Set Astronomy Picture of the Day as wallpaper")
	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.BoolVar(&bpod, "bpod", false, "Set Bing Photo of the Day as wallpaper")
	flag.StringVar(&bpodAPI, "bpod-api", "https://www.bing.com/HPImageArchive.aspx", "BPOD API URL")

	flag.DurationVar(&timeout, "timeout", 16, "Timeout for http client")

	flag.Parse()

	if len(imgPath) > 0 {
		err = setWall(imgPath)
		errChk(err)
		return
	}

	if apod {
		apodI := make(map[string]string)
		apodI["api"] = apodAPI
		apodI["apiKey"] = apodAPIKey

		err = setWallFromAPOD(apodI)
		errChk(err)
		return
	}

	if bpod {
		bpodI := make(map[string]string)
		bpodI["api"] = bpodAPI

		err = setWallFromBPOD(bpodI)
		errChk(err)
		return
	}
}

// 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
}

// Get url of Bing Photo of the Day & pass it to setWall()
func setWallFromBPOD(bpodI map[string]string) error {
	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, bpodI["api"], nil)
	if err != nil {
		return err
	}
	q := req.URL.Query()
	q.Add("format", "js")
	q.Add("n", "1")
	req.URL.RawQuery = q.Encode()

	res, err := getRes(req)
	if err != nil {
		fmt.Printf("Error: GET %s\n", bpodI["api"])
		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
	}

	// Set Bing Photo of the Day as wallpaper
	err = setWall(fmt.Sprintf("%s%s", "https://www.bing.com", bpodNow.Image[0].URL))
	return err
}

// Get url of Astronomy Picture of the Day & pass it to setWall()
func setWallFromAPOD(apodI map[string]string) error {
	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, apodI["api"], nil)
	if err != nil {
		return err
	}
	q := req.URL.Query()
	q.Add("api_key", apodI["apiKey"])
	req.URL.RawQuery = q.Encode()

	res, err := getRes(req)
	if err != nil {
		fmt.Printf("Error: GET %s\n", apodI["api"])
		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
	}

	// Set Astronomy Picture of the Day as wallpaper
	err = setWall(apodNow.HDURL)
	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)
	}
}