Code upload

This commit is contained in:
nxshock 2021-03-19 22:27:25 +05:00
parent 2880e52a08
commit b146c2bc76
18 changed files with 215 additions and 0 deletions

7
README.md Normal file
View file

@ -0,0 +1,7 @@
# trayweather
Простой индикатор погоды в трее.
Доступные источники погоды:
* [Yandex](https://yandex.ru/pogoda)

8
api.go Normal file
View file

@ -0,0 +1,8 @@
package main
type WeatherData interface {
CurrentTemperature() float64
FeelsLikeTemperature() float64
Description() string
IconName() string
}

38
config.go Normal file
View file

@ -0,0 +1,38 @@
package main
import (
"log"
"time"
"github.com/ilyakaznacheev/cleanenv"
"github.com/ncruces/zenity"
)
type Config struct {
CityName string `toml:"CityName" env:"CITY_NAME"`
UpdatePeriod time.Duration `toml:"UpdatePeriod", env:"UPDATE_PERIOD"`
}
var config Config
func init() {
log.SetFlags(0)
err := cleanenv.ReadConfig("config.toml", &config)
if err != nil {
zenity.Notify("Ошибка при чтении настроек из файла config.toml:\n" + err.Error())
log.Fatalln(err)
}
if config.CityName == "" {
zenity.Notify("Город (поле CityName) не может быть пустым.")
log.Fatalln("Город (поле CityName) не может быть пустым.")
}
log.Println(config.UpdatePeriod)
if config.UpdatePeriod < time.Minute {
log.Printf("Частота обновлений слишком низкая (%s), будет установлено значение в одну минуту.")
config.UpdatePeriod = time.Minute
}
}

2
config.toml Normal file
View file

@ -0,0 +1,2 @@
CityName = "Moscow"
UpdatePeriod = 300_000_000_000 # Кол-во минут * 1_000_000_000

BIN
icons/01d.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
icons/02d.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
icons/03d.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
icons/04d.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
icons/09d.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
icons/10d.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
icons/11d.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
icons/13d.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
icons/50d.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
icons/exit.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
icons/unknown.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

69
main.go Normal file
View file

@ -0,0 +1,69 @@
package main
import (
"embed"
"fmt"
"log"
"net/http"
"os"
"time"
"github.com/getlantern/systray"
"github.com/nxshock/trayweather/yandex"
)
//go:embed icons/*.ico
var icons embed.FS
func init() {
log.SetFlags(0)
http.DefaultClient.Timeout = 10 * time.Second
}
func main() {
systray.Run(onReady, nil)
}
func onReady() {
setTrayIcon("unknown.ico")
go update()
mQuit := systray.AddMenuItem("Выход", "Выйти из приложения")
exitIcon, err := icons.ReadFile("icons/exit.ico")
if err != nil {
log.Fatalln(err)
}
mQuit.SetIcon(exitIcon)
go func() {
<-mQuit.ClickedCh
os.Exit(0)
}()
}
func update() {
for {
c, err := yandex.Get(config.CityName)
if err != nil {
systray.SetTooltip(err.Error())
setTrayIcon("unknown")
time.Sleep(time.Minute)
continue
}
systray.SetTooltip(fmt.Sprintf("%s\n%.1f °C (%.1f °C)", c.Description(), c.CurrentTemperature(), c.FeelsLikeTemperature()))
setTrayIcon(c.IconName())
time.Sleep(config.UpdatePeriod)
}
}
func setTrayIcon(name string) error {
b, err := icons.ReadFile("icons/" + name)
if err != nil {
return err
}
systray.SetIcon(b)
return nil
}

1
make.bat Normal file
View file

@ -0,0 +1 @@
go build -ldflags "-H=windowsgui -linkmode=external -s -w" -buildmode=pie -trimpath

90
yandex/api.go Normal file
View file

@ -0,0 +1,90 @@
package yandex
import (
"fmt"
"net/http"
"strconv"
"strings"
"github.com/PuerkitoBio/goquery"
)
type WeatherData struct {
currentTemperature float64
feelsLikeTemperature float64
description string
iconURL string
}
func (w *WeatherData) CurrentTemperature() float64 {
return w.currentTemperature
}
func (w *WeatherData) FeelsLikeTemperature() float64 {
return w.feelsLikeTemperature
}
func (w *WeatherData) Description() string {
return w.description
}
func (w *WeatherData) IconName() string {
switch w.description {
case "Ясно":
return "01d.ico"
case "Облачно с прояснениями":
return "02d.ico"
case "Пасмурно":
return "03d.ico"
case "Небольшой снег":
return "09d.ico"
case "Снег":
return "13d.ico"
}
return ""
}
func Get(cityName string) (*WeatherData, error) {
url := fmt.Sprintf("https://yandex.ru/pogoda/%s", strings.ToLower(cityName))
resp, err := http.Get(url)
if err != nil {
return nil, err
}
doc, err := goquery.NewDocumentFromResponse(resp)
if err != nil {
return nil, err
}
currentTemp, err := parseFloat(doc.Find("div.fact__temp > span.temp__value").Text())
if err != nil {
return nil, fmt.Errorf("parse current temperature error: %v", err)
}
feelsLikeTemp, err := parseFloat(doc.Find("div.fact__feels-like > div.term__value span.temp__value").Text())
if err != nil {
return nil, fmt.Errorf("parse feels like temperature error: %v", err)
}
wd := &WeatherData{
currentTemperature: currentTemp,
feelsLikeTemperature: feelsLikeTemp,
description: doc.Find("div.link__condition").Text(),
iconURL: doc.Find("div.fact__temp-wrap img.fact__icon").AttrOr("src", "")}
return wd, nil
}
func parseFloat(s string) (float64, error) {
var b []rune
s = strings.ReplaceAll(s, ",", ".")
s = strings.ReplaceAll(s, "", "-")
for _, r := range []rune(s) {
if (r >= '0' && r <= '9') || (r == '+' || r == '-') || (r == '.') {
b = append(b, r)
}
}
return strconv.ParseFloat(string(b), 32)
}