bot.go 4.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. package main
  2. import (
  3. "container/heap"
  4. "encoding/json"
  5. "errors"
  6. "fmt"
  7. "github.com/jasonlvhit/gocron"
  8. "io"
  9. "log"
  10. "os"
  11. "regexp"
  12. "strconv"
  13. "strings"
  14. "time"
  15. )
  16. var songs SongPriorityQueue
  17. var credentials struct {
  18. APIURL string
  19. UserName string
  20. Password string
  21. }
  22. func appendSong(wikiText string, author string, newSong string) string {
  23. const AUTHOR_MARK = "<!-- Lisääjä -->"
  24. const SONG_MARK = "<!-- Kappale -->"
  25. lines := strings.Split(wikiText, "\n")
  26. authorPrevIndex := -2
  27. changedLines := make([]string, 0, len(lines))
  28. for index, line := range lines {
  29. if strings.Index(line, AUTHOR_MARK) != -1 && strings.Index(line, author) != -1 {
  30. authorPrevIndex = index
  31. }
  32. if authorPrevIndex == (index-1) && strings.Index(line, SONG_MARK) != -1 {
  33. changedLines = append(changedLines, "| "+SONG_MARK+" "+newSong)
  34. } else {
  35. changedLines = append(changedLines, line)
  36. }
  37. }
  38. return strings.Join(changedLines, "\n")
  39. }
  40. func addSong(title string, week int, author string, song string) (bool, error) {
  41. wiki := CreateWikiClient(credentials.APIURL, credentials.UserName, credentials.Password)
  42. sections, err := wiki.GetWikiPageSections(title)
  43. if err != nil {
  44. return false, err
  45. }
  46. numberReg, _ := regexp.Compile("\\d+")
  47. for _, section := range sections {
  48. weekStr := numberReg.FindString(section.title)
  49. if weekStr != "" {
  50. weekNumber, _ := strconv.Atoi(weekStr)
  51. if weekNumber == week {
  52. wikiText, err := wiki.GetWikiPageSectionText(title, section.index)
  53. if err != nil {
  54. return false, err
  55. }
  56. changedWikiText := appendSong(wikiText, author, song)
  57. return wiki.EditWikiPageSection(title, section.index, changedWikiText,
  58. fmt.Sprintf("Added week %d song for %s", week, author))
  59. }
  60. }
  61. }
  62. return false, errors.New("Could not find matching section")
  63. }
  64. func songSynced(syncedWeek int) error {
  65. v, err := loadDb()
  66. if err != nil {
  67. return err
  68. }
  69. synced := false
  70. for _, song := range v.Songs {
  71. if song.Week == syncedWeek {
  72. song.Sync = true
  73. synced = true
  74. err := saveDb(v)
  75. if err != nil {
  76. return err
  77. }
  78. }
  79. }
  80. if !synced {
  81. return errors.New("No week matched from JSON for synced song")
  82. }
  83. return errors.New("Week not found")
  84. }
  85. func getSongs() (SongPriorityQueue, error) {
  86. dbSongs, err := loadDb()
  87. if err != nil {
  88. return nil, err
  89. }
  90. songs := make(SongPriorityQueue, len(dbSongs.Songs))
  91. for index, songObj := range dbSongs.Songs {
  92. songs[index] = &Song{
  93. time: targetTime(songObj),
  94. song: songEntryWikiText(songObj),
  95. week: songObj.Week,
  96. sync: songObj.Sync,
  97. index: index,
  98. }
  99. }
  100. heap.Init(&songs)
  101. for len(songs) > 0 && songs[0].sync {
  102. heap.Pop(&songs)
  103. }
  104. return songs, nil
  105. }
  106. func task() {
  107. now := time.Now()
  108. if len(songs) > 0 && songs[0].time.Before(now) {
  109. fmt.Println("Time has passed for " + songs[0].song)
  110. success, err := addSong("Levyraati 2018", songs[0].week, "Lamperi", songs[0].song)
  111. if err != nil {
  112. log.Fatal(err)
  113. }
  114. if success {
  115. err := songSynced(songs[0].week)
  116. if err == nil {
  117. heap.Pop(&songs)
  118. } else {
  119. fmt.Println("Error received:", err)
  120. }
  121. }
  122. }
  123. }
  124. func initCreds() error {
  125. f, err := os.Open("credentials.json")
  126. if err != nil {
  127. return err
  128. }
  129. defer f.Close()
  130. if err != nil {
  131. log.Fatal(err)
  132. return err
  133. }
  134. dec := json.NewDecoder(f)
  135. for {
  136. if err := dec.Decode(&credentials); err == io.EOF {
  137. break
  138. } else if err != nil {
  139. log.Fatal(err)
  140. }
  141. }
  142. return nil
  143. }
  144. func targetTime(entry *SongEntry) time.Time {
  145. yearStart, _ := time.Parse(time.RFC3339, "2018-01-01T00:00:00+02:00")
  146. target := yearStart.AddDate(0, 0, (entry.Week-1)*7)
  147. return target
  148. }
  149. func songEntryWikiText(entry *SongEntry) string {
  150. return songWikiText(entry.URL, entry.Artist, entry.Title)
  151. }
  152. func songWikiText(url string, artist string, title string) string {
  153. return "[" + url + " " + artist + " - " + title + "]"
  154. }
  155. func main() {
  156. err := initCreds()
  157. if err != nil {
  158. panic(err)
  159. }
  160. songs, err = getSongs()
  161. if err != nil {
  162. panic(err)
  163. }
  164. modifiedSongChan := make(chan *SongEntry)
  165. go func() {
  166. webStart(modifiedSongChan)
  167. }()
  168. go func() {
  169. for {
  170. newSong := <-modifiedSongChan
  171. matched := false
  172. for _, song := range songs {
  173. if song.week == newSong.Week {
  174. song.song = songEntryWikiText(newSong)
  175. song.sync = newSong.Sync
  176. matched = true
  177. log.Printf("Updated song for week %d, artist: %s, title: %s, URL: %s, time: %v",
  178. newSong.Week, newSong.Artist, newSong.Title, newSong.URL, song.time)
  179. }
  180. }
  181. if !matched {
  182. song := &Song{
  183. time: targetTime(newSong),
  184. song: songEntryWikiText(newSong),
  185. week: newSong.Week,
  186. sync: newSong.Sync,
  187. index: len(songs),
  188. }
  189. heap.Push(&songs, song)
  190. log.Printf("Added song for week %d, artist: %s, title: %s, URL: %s, time: %v",
  191. newSong.Week, newSong.Artist, newSong.Title, newSong.URL, song.time)
  192. }
  193. }
  194. }()
  195. gocron.Every(1).Second().Do(task)
  196. <-gocron.Start()
  197. }