summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--README.org31
-rw-r--r--cmd/cetus-nasa/cetus-nasa.go105
-rw-r--r--pkg/nasa/apod.go109
3 files changed, 245 insertions, 0 deletions
diff --git a/README.org b/README.org
index 9363c21..9985136 100644
--- a/README.org
+++ b/README.org
@@ -7,6 +7,37 @@ sources for fetching the background.
 
 *Dependency*: [[https://feh.finalrewind.org/][feh]]
 
+* NASA Astronomy Picture of the Day
+cetus-nasa uses NASA's API to get the Astronomy Picture of the Day.
+** Features
+- set APOD as background
+- fetch information on APOD
+- choose custom date
+- choose date randomly
+** Examples
+#+BEGIN_SRC sh
+# set currently APOD as background
+cetus-nasa
+
+# set date randomly
+cetus-nasa -random
+
+# set 2020-01-05 APOD as background
+cetus-nasa -date 2020-01-05
+
+# change api endpoint & api key
+cetus-nasa -api https://api.nasa.gov/planetary/apod \
+           -api-key DEMO_KEY
+
+# don't set background, just fetch information
+cetus-nasa -fetch-only
+
+# don't output anything
+cetus-nasa -quiet
+
+# don't set background, just fetch & don't output anything
+cetus-nasa -quiet -fetch-only # why would anyone do this?
+#+END_SRC
 * Demo
 I just run some cetus commands on my computer, nothing fancy. I'll make better
 demo videos someday.
diff --git a/cmd/cetus-nasa/cetus-nasa.go b/cmd/cetus-nasa/cetus-nasa.go
new file mode 100644
index 0000000..96b83fc
--- /dev/null
+++ b/cmd/cetus-nasa/cetus-nasa.go
@@ -0,0 +1,105 @@
+// 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 (
+	"flag"
+	"fmt"
+	"log"
+	"time"
+
+	"framagit.org/andinus/cetus/pkg"
+	"framagit.org/andinus/cetus/pkg/nasa"
+)
+
+var (
+	quiet     bool
+	fetchOnly bool
+
+	api         string
+	apiKey      string
+	date        string
+	random      bool
+	dateHelp    string
+	dateDefault string
+	timeout     time.Duration
+)
+
+func main() {
+	var (
+		picturePath string
+		apodRes     nasa.APOD
+		err         error
+		apodInfo    map[string]string
+	)
+
+	dateHelp = fmt.Sprintf("Choose a random date between 1995-06-16 & %s",
+		time.Now().UTC().Format("2006-01-02"))
+	dateDefault = time.Now().UTC().Format("2006-01-02")
+
+	parseFlags()
+
+	// Convert timeout to seconds
+	timeout = timeout * time.Second
+
+	if random {
+		date = nasa.RandDate()
+	}
+
+	apodInfo = make(map[string]string)
+	apodInfo["api"] = api
+	apodInfo["apiKey"] = apiKey
+	apodInfo["date"] = date
+
+	apodRes, err = nasa.APODPath(apodInfo, timeout)
+	if err != nil {
+		if len(apodRes.Msg) != 0 {
+			log.Println("Message: ", apodRes.Msg)
+		}
+		log.Fatal(err)
+	}
+
+	if !quiet {
+		fmt.Printf("Title: %s\n\n", apodRes.Title)
+		fmt.Printf("Copyright: %s\n", apodRes.Copyright)
+		fmt.Printf("Date: %s\n\n", apodRes.Date)
+		fmt.Printf("URL: %s\n\n", apodRes.HDURL)
+		fmt.Printf("Explanation: %s\n", apodRes.Explanation)
+	}
+
+	// if fetchOnly is true then don't set background
+	if fetchOnly {
+		return
+	}
+	picturePath = apodRes.HDURL
+	err = background.Set(picturePath)
+	if err != nil {
+		log.Fatal(err)
+	}
+}
+
+func parseFlags() {
+	flag.BoolVar(&quiet, "quiet", false, "No output")
+	flag.BoolVar(&fetchOnly, "fetch-only", false, "Don't set background, only fetch info")
+	flag.BoolVar(&random, "random", false, dateHelp)
+
+	flag.StringVar(&api, "api", "https://api.nasa.gov/planetary/apod", "APOD API URL")
+	flag.StringVar(&apiKey, "api-key", "DEMO_KEY", "api.nasa.gov key for expanded usage")
+	flag.StringVar(&date, "date", dateDefault, "Date of the APOD image to retrieve")
+
+	flag.DurationVar(&timeout, "timeout", 32*time.Second, "Timeout for http client in seconds")
+	flag.Parse()
+
+}
diff --git a/pkg/nasa/apod.go b/pkg/nasa/apod.go
new file mode 100644
index 0000000..62eea96
--- /dev/null
+++ b/pkg/nasa/apod.go
@@ -0,0 +1,109 @@
+// 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 nasa
+
+import (
+	"encoding/json"
+	"fmt"
+	"io/ioutil"
+	"math/rand"
+	"net/http"
+	"regexp"
+	"time"
+)
+
+// APOD holds responses
+type APOD struct {
+	Copyright      string `json:"copyright"`
+	Date           string `json:"date"`
+	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"`
+
+	Code int    `json:"code"`
+	Msg  string `json:"msg"`
+}
+
+// RandDate returns a random date between 1995-06-16 & today
+func RandDate() string {
+	var (
+		min   int64
+		max   int64
+		sec   int64
+		delta int64
+		date  string
+	)
+	min = time.Date(1995, 6, 16, 0, 0, 0, 0, time.UTC).Unix()
+	max = time.Now().UTC().Unix()
+	delta = max - min
+
+	sec = rand.Int63n(delta) + min
+	date = time.Unix(sec, 0).Format("2006-01-02")
+
+	return date
+}
+
+// APODPath returns Astronomy Picture of the Day path
+func APODPath(apodInfo map[string]string, timeout time.Duration) (APOD, error) {
+	var err error
+	apodRes := APOD{}
+
+	// validate date
+	re := regexp.MustCompile("((19|20)\\d\\d)-(0?[1-9]|1[012])-(0?[1-9]|[12][0-9]|3[01])")
+	if !re.MatchString(apodInfo["date"]) {
+		return apodRes, fmt.Errorf("%s does not match format 'YYYY-MM-DD'", apodInfo["date"])
+	}
+
+	client := http.Client{
+		Timeout: time.Second * timeout,
+	}
+
+	req, err := http.NewRequest(http.MethodGet, apodInfo["api"], nil)
+	if err != nil {
+		return apodRes, err
+	}
+	q := req.URL.Query()
+	q.Add("api_key", apodInfo["apiKey"])
+	q.Add("date", apodInfo["date"])
+	req.URL.RawQuery = q.Encode()
+
+	res, err := client.Do(req)
+
+	if err != nil {
+		fmt.Printf("Error: GET %s\n", apodInfo["api"])
+		return apodRes, err
+	}
+	defer res.Body.Close()
+
+	resBody, err := ioutil.ReadAll(res.Body)
+	if err != nil {
+		return apodRes, err
+	}
+
+	err = json.Unmarshal([]byte(resBody), &apodRes)
+	if err != nil {
+		return apodRes, err
+	}
+
+	if res.StatusCode != 200 {
+		return apodRes, fmt.Errorf("Unexpected response status code received: %d %s",
+			res.StatusCode, http.StatusText(res.StatusCode))
+	}
+
+	return apodRes, err
+}