-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.go
139 lines (124 loc) · 3.38 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
package main
import (
"alertt/icon"
"alertt/systray"
"context"
"errors"
"fmt"
"net/http"
"os"
"path/filepath"
"runtime"
"time"
"github.com/gen2brain/beeep"
"github.com/k-x7/eventt"
"golang.org/x/exp/slog"
)
const (
addr = "localhost"
port = "29172"
dir = "/events"
title = "Alertt"
desc = "monitor Sonarr events and show system notifications"
poster = "Sonarr/MediaCover/%d/poster-250.jpg"
)
var (
iconPath string
)
var server *http.Server = &http.Server{
Addr: addr + ":" + port,
Handler: nil,
}
func main() {
systray.Run(onReady, onExit)
}
func onReady() {
setupIcon()
systray.SetupTray(icon.IconTray, title, desc)
setupSonarEvents()
}
func setupIcon() {
// for system notification icon if poster not found locally
tmp := os.TempDir()
iconPath = filepath.Join(tmp, "/gopher.png")
if err := os.WriteFile(iconPath, icon.IconPoster, 0644); err != nil {
slog.Error("can't save icon to temp dir", err)
systray.Quit()
}
}
func setupSonarEvents() {
// create sonarr events handler
events := eventt.SonarrTriggers{
// Log on errors
LogOnError: true,
// on grab show series title and session/episode number and release name
// also include poster for the series if found
OnGrab: func(event eventt.GrabEvent) {
if err := beeep.Notify(
fmt.Sprintf("Grabbed: '%s' S:%d, E:%d", event.Series.Title, event.Episodes[0].SeasonNumber, event.Episodes[0].EpisodeNumber),
event.Release.ReleaseTitle,
getPosterFromLocal(event.Series.ID),
); err != nil {
slog.Error("can't show notification for grab", err)
}
},
// on download show series title and session/episode number and saved location
// also include poster for the series if found
// Note if there is any action
OnDownload: func(event eventt.DownloadEvent) {
if err := beeep.Notify(
fmt.Sprintf("Downloaded: '%s' S:%d, E:%d", event.Series.Title, event.Episodes[0].SeasonNumber, event.Episodes[0].EpisodeNumber),
event.EpisodeFile.Path,
getPosterFromLocal(event.Series.ID),
); err != nil {
slog.Error("can't show notification for download", err)
}
},
}
slog.Info("start server", "host", addr, "port", port, "url", "http://"+addr+":"+port+dir)
http.HandleFunc(dir, events.Monitor)
if err := server.ListenAndServe(); err != nil {
// if application quit don't show error
if !errors.Is(err, http.ErrServerClosed) {
slog.Error("error running http server", err)
}
systray.Quit()
}
}
func onExit() {
// shutdown http when exist
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := server.Shutdown(ctx); err != nil {
slog.Error("error shutdown http server", err)
}
}
// get poster path from local sonarr dir based on series id
func getPosterFromLocal(id int) string {
posterPath := iconPath
switch runtime.GOOS {
case "windows":
posterPath = filepath.Join("C:/ProgramData", fmt.Sprintf(poster, id))
case "linux":
case "darwin":
home, err := os.UserHomeDir()
if err != nil {
home = "~"
}
posterPath = filepath.Join(home, ".config", fmt.Sprintf(poster, id))
}
if exist, err := exists(posterPath); !exist || err != nil {
posterPath = iconPath
}
return posterPath
}
// check if file exist or not with error if any
func exists(name string) (bool, error) {
if _, err := os.Stat(name); err == nil {
return true, nil
} else if errors.Is(err, os.ErrNotExist) {
return false, nil
} else {
return false, err
}
}