Passed
Push — master ( 55e83b...d73a45 )
by Viktor
01:36
created

darksky.DarkSkyData.TZTime   A

Complexity

Conditions 1

Size

Total Lines 2
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nop 1
dl 0
loc 2
rs 10
c 0
b 0
f 0
1
package darksky
2
3
import (
4
	"bytes"
5
	"encoding/json"
6
	"fmt"
7
	"github.com/FlameInTheDark/dtbot/api/location"
8
	"github.com/FlameInTheDark/dtbot/bot"
9
	"github.com/fogleman/gg"
10
	"image/png"
11
	"net/http"
12
	"strings"
13
	"time"
14
)
15
16
type DarkSkyResponse struct {
0 ignored issues
show
introduced by
exported type DarkSkyResponse should have comment or be unexported
Loading history...
introduced by
type name will be used as darksky.DarkSkyResponse by other packages, and that stutters; consider calling this Response
Loading history...
17
	Latitude  float32       `json:"latitude"`
18
	Longitude float32       `json:"longitude"`
19
	Timezone  string        `json:"timezone"`
20
	Currently DarkSkyData   `json:"currently"`
21
	Hourly    DarkSkyHourly `json:"hourly"`
22
	Daily     DarkSkyDaily  `json:"daily"`
23
	Flags     DarkSkyFlags  `json:"flags"`
24
	Offset    int64           `json:"offset"`
25
}
26
27
type DarkSkyData struct {
0 ignored issues
show
introduced by
exported type DarkSkyData should have comment or be unexported
Loading history...
introduced by
type name will be used as darksky.DarkSkyData by other packages, and that stutters; consider calling this Data
Loading history...
28
	Time                int64     `json:"time"`
29
	Summary             string  `json:"summary"`
30
	Icon                string  `json:"icon"`
31
	PrecipIntensity     int64     `json:"precipIntensity"`
32
	PrecipProbability   int64     `json:"precipProbability"`
33
	Temperature         float32 `json:"temperature"`
34
	ApparentTemperature float32 `json:"apparentTemperature"`
35
	DewPoint            float32 `json:"dewPoint"`
36
	Humidity            float32 `json:"humidity"`
37
	Pressure            float32 `json:"pressure"`
38
	WindSpeed           float32 `json:"windSpeed"`
39
	WindGust            float32 `json:"windGust"`
40
	WindBearing         int64     `json:"windBearing"`
41
	CloudCover          float32 `json:"cloudCover"`
42
	UVIndex             int64     `json:"uvIndex"`
43
	Visibility          float32 `json:"visibility"`
44
	Ozone               float32 `json:"ozone"`
45
}
46
47
type DarkSkyHourly struct {
0 ignored issues
show
introduced by
exported type DarkSkyHourly should have comment or be unexported
Loading history...
introduced by
type name will be used as darksky.DarkSkyHourly by other packages, and that stutters; consider calling this Hourly
Loading history...
48
	Summary string        `json:"summary"`
49
	Icon    string        `json:"icon"`
50
	Data    []DarkSkyData `json:"data"`
51
}
52
53
type DarkSkyDaily struct {
0 ignored issues
show
introduced by
exported type DarkSkyDaily should have comment or be unexported
Loading history...
introduced by
type name will be used as darksky.DarkSkyDaily by other packages, and that stutters; consider calling this Daily
Loading history...
54
	Summary string           `json:"summary"`
55
	Icon    string           `json:"icon"`
56
	Data    []DarkSkyDayData `json:"data"`
57
}
58
59
type DarkSkyDayData struct {
0 ignored issues
show
introduced by
exported type DarkSkyDayData should have comment or be unexported
Loading history...
introduced by
type name will be used as darksky.DarkSkyDayData by other packages, and that stutters; consider calling this DayData
Loading history...
60
	Time                        int64     `json:"time"`
61
	Summary                     string  `json:"summary"`
62
	Icon                        string  `json:"icon"`
63
	SunriseTime                 int64     `json:"sunriseTime"`
64
	SunsetTime                  int64     `json:"sunsetTime"`
65
	MoonPhase                   float32 `json:"moonPhase"`
66
	PrecipIntensity             float32 `json:"precipIntensity"`
67
	PrecipIntensityMax          float32 `json:"precipIntensityMax"`
68
	PrecipIntensityMaxTime      int64     `json:"precipIntensityMaxTime"`
69
	PrecipProbability           float32 `json:"precipProbability"`
70
	PrecipAccumulation          float32 `json:"precipAccumulation"`
71
	PrecipType                  string  `json:"precipType"`
72
	TemperatureHigh             float32 `json:"temperatureHigh"`
73
	TemperatureHighTime         int64     `json:"temperatureHighTime"`
74
	TemperatureLow              float32 `json:"temperatureLow"`
75
	TemperatureLowTime          int64     `json:"temperatureLowTime"`
76
	ApparentTemperatureHigh     float32 `json:"apparentTemperatureHigh"`
77
	ApparentTemperatureHighTime int64     `json:"apparentTemperatureHighTime"`
78
	ApparentTemperatureLow      float32 `json:"apparentTemperatureLow"`
79
	ApparentTemperatureLowTime  int64     `json:"apparentTemperatureLowTime"`
80
	DewPoint                    float32 `json:"dewPoint"`
81
	Humidity                    float32 `json:"humidity"`
82
	Pressure                    float32 `json:"pressure"`
83
	WindSpeed                   float32 `json:"windSpeed"`
84
	WindGust                    float32 `json:"windGust"`
85
	WindGustTime                int64     `json:"windGustTime"`
86
	WindBearing                 int64     `json:"windBearing"`
87
	CloudCover                  float32 `json:"cloudCover"`
88
	UVIndex                     int64     `json:"uvIndex"`
89
	UVIndexTime                 int64     `json:"uvIndexTime"`
90
	Visibility                  float32 `json:"visibility"`
91
	Ozone                       float32 `json:"ozone"`
92
	TemperatureMin              float32 `json:"temperatureMin"`
93
	TemperatureMinTime          int64     `json:"temperatureMinTime"`
94
	TemperatureMax              float32 `json:"temperatureMax"`
95
	TemperatureMaxTime          int64     `json:"temperatureMaxTime"`
96
	ApparentTemperatureMin      float32 `json:"apparentTemperatureMin"`
97
	ApparentTemperatureMinTime  int64     `json:"apparentTemperatureMinTime"`
98
	ApparentTemperatureMax      float32 `json:"apparentTemperatureMax"`
99
	ApparentTemperatureMaxTime  int64     `json:"apparentTemperatureMaxTime"`
100
}
101
102
type DarkSkyFlags struct {
0 ignored issues
show
introduced by
exported type DarkSkyFlags should have comment or be unexported
Loading history...
introduced by
type name will be used as darksky.DarkSkyFlags by other packages, and that stutters; consider calling this Flags
Loading history...
103
	Sources        []string `json:"sources"`
104
	NearestStation float32  `json:"nearest-station"`
105
	Units          string   `json:"units"`
106
}
107
108
func (d DarkSkyData) TZTime(tz int) time.Time {
0 ignored issues
show
introduced by
exported method DarkSkyData.TZTime should have comment or be unexported
Loading history...
109
	return time.Unix(d.Time, 0).UTC().Add(time.Hour * time.Duration(tz))
110
}
111
112
func GetWeatherImage(ctx *bot.Context) (buf *bytes.Buffer, err error) {
0 ignored issues
show
introduced by
exported function GetWeatherImage should have comment or be unexported
Loading history...
113
	var (
114
		forecast DarkSkyResponse
115
		city     = ctx.GetGuild().WeatherCity
116
	)
117
118
	if len(ctx.Args) > 0 {
119
		city = strings.Join(ctx.Args, "+")
120
	}
121
122
	loc, err := location.New(ctx.Conf.General.GeonamesUsername, city)
123
	if err != nil {
124
		fmt.Printf("Location API: %v", err)
125
		return
126
	}
127
128
	cityName := loc.Geonames[0].CountryName + ", " + loc.Geonames[0].Name
129
130
	// Get coordinates and get weather data
131
	newlat, newlng := loc.GetCoordinates()
132
	resp, err := http.Get(fmt.Sprintf("https://api.darksky.net/forecast/%v/%v,%v?units=ca&lang=%v",
133
		ctx.Conf.DarkSky.Token, newlat, newlng, ctx.Conf.General.Language))
134
	if err != nil {
135
		fmt.Printf("Weather API: %v", err)
136
		return
137
	}
138
139
	err = json.NewDecoder(resp.Body).Decode(&forecast)
140
	if err != nil {
141
		fmt.Printf("Weather Decode: %v", err)
142
		return
143
	}
144
145
	gc := gg.NewContext(400, 650)
146
	gc.SetRGBA(0, 0, 0, 0)
147
	gc.Clear()
148
149
	// Template
150
	gc.SetRGB255(242, 97, 73)
151
	gc.DrawRoundedRectangle(0, 0, 400, 650, 10)
152
	gc.Fill()
153
154
	// Weather lines
155
	gc.SetRGB255(234, 89, 65)
156
	gc.DrawRectangle(0, 250, 400, 100)
157
	gc.DrawRectangle(0, 450, 400, 100)
158
	gc.Fill()
159
160
	gc.SetLineWidth(2)
161
	gc.SetRGBA(0, 0, 0, 0.05)
162
	gc.DrawLine(0, 250, 400, 250)
163
	gc.DrawLine(0, 349, 400, 348)
164
	gc.DrawLine(0, 450, 400, 450)
165
	gc.DrawLine(0, 549, 400, 548)
166
	gc.Stroke()
167
168
	// Text
169
	if err := gc.LoadFontFace("lato.ttf", 20); err != nil {
170
		panic(err)
171
	}
172
	// Header
173
	gc.SetRGBA(1, 1, 1, 0.7)
174
	gc.DrawStringAnchored(cityName, 10, 15, 0, 0.5)
175
	gc.SetRGBA(1, 1, 1, 0.4)
176
	gc.DrawStringAnchored(time.Now().Format("Jan 2, 2006"), 280, 15, 0, 0.5)
177
178
	// First weather data
179
	gc.SetRGBA(1, 1, 1, 0.5)
180
	if err := gc.LoadFontFace("lato.ttf", 30); err != nil {
181
		panic(err)
182
	}
183
	gc.DrawStringAnchored(fmt.Sprintf("%.2v:00", forecast.Currently.TZTime(ctx.Conf.General.Timezone).Hour()), 50, 200, 0.5, 0.5)
184
	gc.DrawStringAnchored(fmt.Sprintf("H:%v%%", forecast.Currently.Humidity), 200, 200, 0.5, 0.5)
185
	gc.DrawStringAnchored(fmt.Sprintf("C:%v%%", int(forecast.Currently.CloudCover)), 350, 200, 0.5, 0.5)
186
187
	gc.SetRGBA(1, 1, 1, 1)
188
	if err := gc.LoadFontFace("lato.ttf", 90); err != nil {
189
		panic(err)
190
	}
191
192
	gc.DrawStringAnchored(fmt.Sprintf("%v°", int(forecast.Currently.Temperature)), 100, 120, 0.5, 0.5)
193
194
	if err := gc.LoadFontFace("owfont-regular.ttf", 90); err != nil {
195
		panic(err)
196
	}
197
198
	gc.DrawStringAnchored(ctx.WeatherCode(fmt.Sprintf("%v", forecast.Currently.Icon)), 250, 120, 0, 0.7)
199
200
	if err := gc.LoadFontFace("lato.ttf", 30); err != nil {
201
		panic(err)
202
	}
203
204
	// Time
205
	gc.DrawStringAnchored(fmt.Sprintf("%.2v:00", forecast.Hourly.Data[1].TZTime(ctx.Conf.General.Timezone).Hour()), 100, 285, 0, 0.5)
206
	gc.DrawStringAnchored(fmt.Sprintf("%.2v:00", forecast.Hourly.Data[2].TZTime(ctx.Conf.General.Timezone).Hour()), 100, 385, 0, 0.5)
207
	gc.DrawStringAnchored(fmt.Sprintf("%.2v:00", forecast.Hourly.Data[3].TZTime(ctx.Conf.General.Timezone).Hour()), 100, 485, 0, 0.5)
208
	gc.DrawStringAnchored(fmt.Sprintf("%.2v:00", forecast.Hourly.Data[4].TZTime(ctx.Conf.General.Timezone).Hour()), 100, 585, 0, 0.5)
209
210
	// Humidity and cloudiness
211
	if err := gc.LoadFontFace("lato.ttf", 20); err != nil {
212
		panic(err)
213
	}
214
	gc.SetRGBA(1, 1, 1, 0.5)
215
216
	gc.DrawStringAnchored(fmt.Sprintf("H:%v%%", forecast.Hourly.Data[1].Humidity), 100, 315, 0, 0.5)
217
	gc.DrawStringAnchored(fmt.Sprintf("H:%v%%", forecast.Hourly.Data[2].Humidity), 100, 415, 0, 0.5)
218
	gc.DrawStringAnchored(fmt.Sprintf("H:%v%%", forecast.Hourly.Data[3].Humidity), 100, 515, 0, 0.5)
219
	gc.DrawStringAnchored(fmt.Sprintf("H:%v%%", forecast.Hourly.Data[4].Humidity), 100, 615, 0, 0.5)
220
221
	gc.DrawStringAnchored(fmt.Sprintf("C:%v%%", int(forecast.Hourly.Data[1].CloudCover)), 170, 315, 0, 0.5)
222
	gc.DrawStringAnchored(fmt.Sprintf("C:%v%%", int(forecast.Hourly.Data[2].CloudCover)), 170, 415, 0, 0.5)
223
	gc.DrawStringAnchored(fmt.Sprintf("C:%v%%", int(forecast.Hourly.Data[3].CloudCover)), 170, 515, 0, 0.5)
224
	gc.DrawStringAnchored(fmt.Sprintf("C:%v%%", int(forecast.Hourly.Data[4].CloudCover)), 170, 615, 0, 0.5)
225
226
	gc.SetRGBA(1, 1, 1, 1)
227
	if err := gc.LoadFontFace("lato.ttf", 50); err != nil {
228
		panic(err)
229
	}
230
231
	// Temperature
232
	gc.DrawStringAnchored(fmt.Sprintf("%v°", int(forecast.Hourly.Data[1].Temperature)), 320, 300, 0.5, 0.5)
233
	gc.DrawStringAnchored(fmt.Sprintf("%v°", int(forecast.Hourly.Data[2].Temperature)), 320, 400, 0.5, 0.5)
234
	gc.DrawStringAnchored(fmt.Sprintf("%v°", int(forecast.Hourly.Data[3].Temperature)), 320, 500, 0.5, 0.5)
235
	gc.DrawStringAnchored(fmt.Sprintf("%v°", int(forecast.Hourly.Data[4].Temperature)), 320, 600, 0.5, 0.5)
236
237
	if err := gc.LoadFontFace("owfont-regular.ttf", 60); err != nil {
238
		panic(err)
239
	}
240
241
	// Weather icon
242
	gc.DrawStringAnchored(ctx.WeatherCode(fmt.Sprintf("%v", forecast.Hourly.Data[1].Icon)), 20, 300, 0, 0.7)
243
	gc.DrawStringAnchored(ctx.WeatherCode(fmt.Sprintf("%v", forecast.Hourly.Data[2].Icon)), 20, 400, 0, 0.7)
244
	gc.DrawStringAnchored(ctx.WeatherCode(fmt.Sprintf("%v", forecast.Hourly.Data[3].Icon)), 20, 500, 0, 0.7)
245
	gc.DrawStringAnchored(ctx.WeatherCode(fmt.Sprintf("%v", forecast.Hourly.Data[4].Icon)), 20, 600, 0, 0.7)
246
247
	buf = new(bytes.Buffer)
248
	pngerr := png.Encode(buf, gc.Image())
249
	if pngerr != nil {
250
		fmt.Printf("Image: %v", pngerr)
251
	}
252
	return
253
}
254