-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
157 lines (137 loc) · 4.51 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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
package main
import (
"log"
"net/http"
"os"
"strings"
"time"
"github.com/gin-gonic/gin"
"rolflewis.com/spotify-status-sync/src/database"
"rolflewis.com/spotify-status-sync/src/routes"
"rolflewis.com/spotify-status-sync/src/slack"
"rolflewis.com/spotify-status-sync/src/spotify"
)
var globalClient *http.Client
func main() {
log.SetFlags(log.LstdFlags | log.Lshortfile)
port := os.Getenv("PORT")
if port == "" {
log.Fatal("$PORT must be set")
}
// Create the global spotify client
globalClient = http.DefaultClient
// Create routes
router := gin.New()
router.Use(gin.Logger())
router.LoadHTMLGlob("pages/*.html")
router.Static("/static", "static")
router.GET("/", func(c *gin.Context) {
c.HTML(http.StatusOK, "index.html", nil)
})
router.GET("/spotify/callback", spotifyCallbackClientInjector)
router.GET("/slack/callback", slackCallbackClientInjector)
router.POST("/slack/events", eventsClientInjector)
router.POST("/slack/interactivity", interactionsClientInjector)
// Database setup
database.ConnectToDatabase()
database.ValidateSchema()
// Kick off the spotify token maintenance routine
go spotifyTokenMaintenance()
// Kick of the the currently playing query loop
go spotifyCurrentlyPlayingLoop()
// Stand up server
routerError := router.Run(":" + port)
if routerError != nil {
log.Fatal("Router Error:", routerError)
}
}
func statusSyncHelper() (int, error) {
// Get all users who have spotify connected
users, usersError := database.GetAllConnectedUsers()
if usersError != nil {
return 0, usersError
}
// Get currently playing for each user
for index, user := range users {
current, currentError := spotify.GetCurrentlyPlayingForUser(user, globalClient)
if currentError != nil {
return index, currentError
}
// Start building new status
var newStatus string
// Conditions where we should submit an empty status
if current != nil && current.IsPlaying {
if current.CurrentlyPlayingType == "track" {
// Build the new status
newStatus = "Listening to \"" + current.Item.Name + "\" by "
// To help in reducing character count, don't include artists in the artists lists
// who are also included in the song name such as "feat. artist name"
reducedArtistList := make([]string, 0)
for _, artist := range current.Item.Artists {
if !strings.Contains(artist.Name, current.Item.Name) {
reducedArtistList = append(reducedArtistList, artist.Name)
}
}
// Build the artists section of the status
for index, artist := range reducedArtistList {
// Comma separated list
if index > 0 {
newStatus += ", "
}
// add artists name
newStatus += artist
}
newStatus += " on Spotify"
} else if current.CurrentlyPlayingType == "episode" {
// Build the new status
newStatus = "Listening to \"" + current.Item.Name + "\" (" + current.Item.Show.Name + ") by " + current.Item.Show.Publisher + " on Spotify"
}
}
// Safeguards against overly long status messages
if len(newStatus) > 100 {
// Fallback to just the name
newStatus = "Listening to \"" + current.Item.Name + "\" on Spotify "
}
// Update the new status
updateError := slack.UpdateUserStatus(user, newStatus, globalClient)
if updateError != nil {
return index, updateError
}
}
// return success
return len(users), nil
}
func spotifyCurrentlyPlayingLoop() {
ticker := time.NewTicker(5 * time.Second)
for {
usersUpdated, updateError := statusSyncHelper()
log.Println("Spotify Currently Playing synced for", usersUpdated, "users.")
if updateError != nil {
log.Println("Spotify Currently Playing Sync exited early due to error:", updateError)
}
<-ticker.C // Block until ticker kicks a tick off
}
}
func spotifyTokenMaintenance() {
ticker := time.NewTicker(15 * time.Minute)
for {
usersRefreshed, refreshError := spotify.RefreshExpiringTokens(globalClient)
log.Println("Spotify token refresh function refreshed", usersRefreshed, "tokens.")
if refreshError != nil {
log.Println("Spotify token refresh function exited early due to error:", refreshError)
}
<-ticker.C // Block until ticker kicks a tick off
}
}
func slackCallbackClientInjector(context *gin.Context) {
routes.SlackCallbackFlow(context, globalClient)
}
func spotifyCallbackClientInjector(context *gin.Context) {
routes.SpotifyCallbackFlow(context, globalClient)
}
func eventsClientInjector(context *gin.Context) {
routes.EventsEndpoint(context, globalClient)
}
func interactionsClientInjector(context *gin.Context) {
routes.InteractivityEndpoint(context, globalClient)
}