|
|
|
//nolint:forbidigo,funlen,nestif,goerr113,gocognit,cyclop
|
|
|
|
package v1
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"encoding/json"
|
|
|
|
"flag"
|
|
|
|
"fmt"
|
|
|
|
"io/ioutil"
|
|
|
|
"net/http"
|
|
|
|
"net/url"
|
|
|
|
"os"
|
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
|
|
|
//nolint:tagliatelle
|
|
|
|
type cond struct {
|
|
|
|
ChanceOfRain string `json:"chanceofrain"`
|
|
|
|
FeelsLikeC int `json:",string"`
|
|
|
|
PrecipMM float32 `json:"precipMM,string"`
|
|
|
|
TempC int `json:"tempC,string"`
|
|
|
|
TempC2 int `json:"temp_C,string"`
|
|
|
|
Time int `json:"time,string"`
|
|
|
|
VisibleDistKM int `json:"visibility,string"`
|
|
|
|
WeatherCode int `json:"weatherCode,string"`
|
|
|
|
WeatherDesc []struct{ Value string }
|
|
|
|
WindGustKmph int `json:",string"`
|
|
|
|
Winddir16Point string
|
|
|
|
WindspeedKmph int `json:"windspeedKmph,string"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type astro struct {
|
|
|
|
Moonrise string
|
|
|
|
Moonset string
|
|
|
|
Sunrise string
|
|
|
|
Sunset string
|
|
|
|
}
|
|
|
|
|
|
|
|
type weather struct {
|
|
|
|
Astronomy []astro
|
|
|
|
Date string
|
|
|
|
Hourly []cond
|
|
|
|
MaxtempC int `json:"maxtempC,string"`
|
|
|
|
MintempC int `json:"mintempC,string"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type loc struct {
|
|
|
|
Query string `json:"query"`
|
|
|
|
Type string `json:"type"`
|
|
|
|
}
|
|
|
|
|
|
|
|
//nolint:tagliatelle
|
|
|
|
type resp struct {
|
|
|
|
Data struct {
|
|
|
|
Cur []cond `json:"current_condition"`
|
|
|
|
Err []struct{ Msg string } `json:"error"`
|
|
|
|
Req []loc `json:"request"`
|
|
|
|
Weather []weather `json:"weather"`
|
|
|
|
} `json:"data"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *global) getDataFromAPI() (*resp, error) {
|
|
|
|
var (
|
|
|
|
ret resp
|
|
|
|
params []string
|
|
|
|
)
|
|
|
|
|
|
|
|
if len(g.config.APIKey) == 0 {
|
|
|
|
return nil, fmt.Errorf("no API key specified. Setup instructions are in the README")
|
|
|
|
}
|
|
|
|
params = append(params, "key="+g.config.APIKey)
|
|
|
|
|
|
|
|
// non-flag shortcut arguments will overwrite possible flag arguments
|
|
|
|
for _, arg := range flag.Args() {
|
|
|
|
if v, err := strconv.Atoi(arg); err == nil && len(arg) == 1 {
|
|
|
|
g.config.Numdays = v
|
|
|
|
} else {
|
|
|
|
g.config.City = arg
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(g.config.City) > 0 {
|
|
|
|
params = append(params, "q="+url.QueryEscape(g.config.City))
|
|
|
|
}
|
|
|
|
params = append(params, "format=json", "num_of_days="+strconv.Itoa(g.config.Numdays), "tp=3")
|
|
|
|
if g.config.Lang != "" {
|
|
|
|
params = append(params, "lang="+g.config.Lang)
|
|
|
|
}
|
|
|
|
|
|
|
|
if g.debug {
|
|
|
|
fmt.Fprintln(os.Stderr, params)
|
|
|
|
}
|
|
|
|
|
|
|
|
res, err := http.Get(wuri + strings.Join(params, "&"))
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
defer res.Body.Close()
|
|
|
|
body, err := ioutil.ReadAll(res.Body)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if g.debug {
|
|
|
|
var out bytes.Buffer
|
|
|
|
|
|
|
|
err := json.Indent(&out, body, "", " ")
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err = out.WriteTo(os.Stderr)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
fmt.Print("\n\n")
|
|
|
|
}
|
|
|
|
|
|
|
|
if g.config.Lang == "" {
|
|
|
|
if err = json.Unmarshal(body, &ret); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if err = g.unmarshalLang(body, &ret); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return &ret, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *global) unmarshalLang(body []byte, r *resp) error {
|
|
|
|
var rv map[string]interface{}
|
|
|
|
if err := json.Unmarshal(body, &rv); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if data, ok := rv["data"].(map[string]interface{}); ok {
|
|
|
|
if ccs, ok := data["current_condition"].([]interface{}); ok {
|
|
|
|
for _, cci := range ccs {
|
|
|
|
cc, ok := cci.(map[string]interface{})
|
|
|
|
if !ok {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
langs, ok := cc["lang_"+g.config.Lang].([]interface{})
|
|
|
|
if !ok || len(langs) == 0 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
weatherDesc, ok := cc["weatherDesc"].([]interface{})
|
|
|
|
if !ok || len(weatherDesc) == 0 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
weatherDesc[0] = langs[0]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ws, ok := data["weather"].([]interface{}); ok {
|
|
|
|
for _, wi := range ws {
|
|
|
|
w, ok := wi.(map[string]interface{})
|
|
|
|
if !ok {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if hs, ok := w["hourly"].([]interface{}); ok {
|
|
|
|
for _, hi := range hs {
|
|
|
|
h, ok := hi.(map[string]interface{})
|
|
|
|
if !ok {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
langs, ok := h["lang_"+g.config.Lang].([]interface{})
|
|
|
|
if !ok || len(langs) == 0 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
weatherDesc, ok := h["weatherDesc"].([]interface{})
|
|
|
|
if !ok || len(weatherDesc) == 0 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
weatherDesc[0] = langs[0]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
var buf bytes.Buffer
|
|
|
|
if err := json.NewEncoder(&buf).Encode(rv); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := json.NewDecoder(&buf).Decode(r); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|