From 8c5c5d61506c66069f9c33cc19b3d81518d52e92 Mon Sep 17 00:00:00 2001 From: serr Date: Mon, 19 May 2025 17:03:18 +0300 Subject: [PATCH] =?UTF-8?q?=D1=82=D0=B5=D0=BF=D0=B5=D1=80=D1=8C=20=D1=81?= =?UTF-8?q?=D0=B5=D1=80=D0=B2=D0=B5=D1=80=20=D1=80=D0=B0=D0=B7=20=D0=B2=20?= =?UTF-8?q?30=20=D1=81=D0=B5=D0=BA=D1=83=D0=BD=D0=B4=20=D0=BE=D0=B1=D0=BD?= =?UTF-8?q?=D0=BE=D0=B2=D0=BB=D1=8F=D0=B5=D1=82=20=D0=BF=D0=BE=D1=81=D0=BB?= =?UTF-8?q?=D0=B5=D0=B4=D0=BD=D0=B8=D0=B9=20=D0=BF=D1=80=D0=BE=D1=81=D0=BB?= =?UTF-8?q?=D1=83=D1=88=D0=B0=D0=BD=D0=BD=D1=8B=D0=B9=20=D1=82=D1=80=D0=B5?= =?UTF-8?q?=D0=BA,=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8=D0=BB=20=D0=BF?= =?UTF-8?q?=D0=BE=D0=BB=D0=B5=20=D0=BF=D0=BE=D0=B4=20=D0=BD=D0=B5=D0=B3?= =?UTF-8?q?=D0=BE=20=D0=B2=20app?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main.go | 16 ++++++++++++- mvc/controllers/lastfm.go | 22 +++-------------- mvc/models/app.go | 13 ++++++---- mvc/models/config.go | 26 ++++++++++---------- mvc/models/lastfm.go | 43 ++++++++++++++++++++++++---------- mvc/views/blocks/header.gohtml | 2 +- tools/ticker.go | 27 +++++++++++++++++++++ 7 files changed, 98 insertions(+), 51 deletions(-) create mode 100644 tools/ticker.go diff --git a/main.go b/main.go index 6282c84..7ef1ddd 100644 --- a/main.go +++ b/main.go @@ -8,6 +8,7 @@ import ( "main/mvc/models" "main/tools" "net/http" + "time" ) func main() { @@ -25,6 +26,19 @@ func main() { // Настройка маршрутов router := setupRoutes(app) + // Запуск тикеров + { + // Обновление последнего прослушанного трека ластфм + tools.Ticker(func() { + var lastTrack string + if lastTrack, err = models.LastFMGetLastTrack(app.Cfg.LastFMUsername, app.Cfg.LastFMToken); err != nil { + log.Println(err) + return + } + app.LastfmLastTrack = lastTrack + }, time.Second*app.Cfg.LastFMUpdateInterval) + } + // Запуск сервера if ok, err := tools.IsIPInUse(app.Cfg.ServerIP); err != nil { log.Fatal(err) @@ -61,7 +75,7 @@ func setupRoutes(app *models.App) *http.ServeMux { // Api { - router.Handle("/api/lastfm", m(controllers.LastfmHandler(app))) + router.Handle("/api/lastfm", m(controllers.LastFMHandler(app))) } return router diff --git a/mvc/controllers/lastfm.go b/mvc/controllers/lastfm.go index b700433..248d3b4 100644 --- a/mvc/controllers/lastfm.go +++ b/mvc/controllers/lastfm.go @@ -2,35 +2,19 @@ package controllers import ( "fmt" - "log" "main/mvc/models" "net/http" ) // Обработчик главной страницы -func LastfmHandler(app *models.App) http.HandlerFunc { +func LastFMHandler(app *models.App) http.HandlerFunc { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - var err error - - resp, err := models.GetRecentTracks(app.Cfg.LastfmUsername, app.Cfg.LastfmToken) - if err != nil { - log.Println(err) - } - - var data string - if len(resp.RecentTracks.Track) > 0 { - track := resp.RecentTracks.Track[0] - data = fmt.Sprintf("%s - %s", track.Name, track.Artist.Name) - } else { - data = "lastfm strange error..." - } - - sendLastfm(w, data) + sendLastFM(w, app.LastfmLastTrack) }) } // Отправляет страницу -func sendLastfm(w http.ResponseWriter, data string) { +func sendLastFM(w http.ResponseWriter, data string) { w.Header().Set("Content-Type", "text/html; charset=utf-8") w.WriteHeader(http.StatusOK) fmt.Fprint(w, data) diff --git a/mvc/models/app.go b/mvc/models/app.go index 4d4297c..9c38268 100644 --- a/mvc/models/app.go +++ b/mvc/models/app.go @@ -7,11 +7,12 @@ import ( ) type App struct { - Cfg *Config // Сонфиг - Posts models_pages.Posts // Посты - Templates *template.Template // Шаблоны страниц - PagesCache *Cache // Кэш (отрендеренные странички) - Version int64 // Время запуска + Cfg *Config // Сонфиг + Posts models_pages.Posts // Посты + Templates *template.Template // Шаблоны страниц + PagesCache *Cache // Кэш (отрендеренные странички) + LastfmLastTrack string // Последний трек, полученный с ластфм + Version int64 // Время запуска } // Инициализирует приложение @@ -36,5 +37,7 @@ func InitApp() (*App, error) { } // Инициализация кэша app.PagesCache = initCache() + // Строка по умолчанию для последнего прослушанного трека + app.LastfmLastTrack = "None" return app, nil } diff --git a/mvc/models/config.go b/mvc/models/config.go index 2a425b2..9134f97 100644 --- a/mvc/models/config.go +++ b/mvc/models/config.go @@ -3,6 +3,7 @@ package models import ( "encoding/json" "os" + "time" ) const ( @@ -10,18 +11,19 @@ const ( ) type Config struct { - PostsDir string - AssetsDir string - TemplatesDir string - TemplatesExt string - LocalIP string - LocalPort string - ServerIP string - ServerPort string - ServerDomain string - Port string - LastfmUsername string - LastfmToken string + PostsDir string + AssetsDir string + TemplatesDir string + TemplatesExt string + LocalIP string + LocalPort string + ServerIP string + ServerPort string + ServerDomain string + Port string + LastFMUsername string + LastFMToken string + LastFMUpdateInterval time.Duration } func loadConfig(configPath string) (*Config, error) { diff --git a/mvc/models/lastfm.go b/mvc/models/lastfm.go index 44aed6b..05af5b5 100644 --- a/mvc/models/lastfm.go +++ b/mvc/models/lastfm.go @@ -7,24 +7,26 @@ import ( "net/http" ) +type LastFMTrack struct { + Name string `json:"name"` + Artist struct { + Name string `json:"#text"` + } `json:"artist"` + Album struct { + Name string `json:"#text"` + } `json:"album"` + Date struct { + Unix string `json:"#text"` + } `json:"date"` +} + type LastFMResponse struct { RecentTracks struct { - Track []struct { - Name string `json:"name"` - Artist struct { - Name string `json:"#text"` - } `json:"artist"` - Album struct { - Name string `json:"#text"` - } `json:"album"` - Date struct { - Unix string `json:"#text"` - } `json:"date"` - } `json:"track"` + Tracks []LastFMTrack `json:"track"` } `json:"recenttracks"` } -func GetRecentTracks(username, apiKey string) (*LastFMResponse, error) { +func LastFMGetRecentTracks(username, apiKey string) (*LastFMResponse, error) { url := fmt.Sprintf("https://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&user=%s&api_key=%s&format=json", username, apiKey) resp, err := http.Get(url) if err != nil { @@ -42,3 +44,18 @@ func GetRecentTracks(username, apiKey string) (*LastFMResponse, error) { return &lastFMResponse, nil } + +func LastFMGetLastTrack(username, apiKey string) (string, error) { + resp, err := LastFMGetRecentTracks(username, apiKey) + if err != nil { + return "", err + } + var data string + if len(resp.RecentTracks.Tracks) > 0 { + track := resp.RecentTracks.Tracks[0] + data = fmt.Sprintf("%s - %s", track.Name, track.Artist.Name) + } else { + return "", fmt.Errorf("len(resp.RecentTracks.Tracks) <= 0") + } + return data, nil +} diff --git a/mvc/views/blocks/header.gohtml b/mvc/views/blocks/header.gohtml index 8a76b27..3a3aa9d 100644 --- a/mvc/views/blocks/header.gohtml +++ b/mvc/views/blocks/header.gohtml @@ -43,7 +43,7 @@ updateLastfm(); - setInterval(updateLastfm, 20000); + setInterval(updateLastfm, 30000); {{ end }} \ No newline at end of file diff --git a/tools/ticker.go b/tools/ticker.go new file mode 100644 index 0000000..7722a8a --- /dev/null +++ b/tools/ticker.go @@ -0,0 +1,27 @@ +package tools + +import "time" + +// Ticker запускает функцию fn с указанным интервалом в отдельной горутине +// Возвращает канал для остановки тикера +func Ticker(fn func(), interval time.Duration) chan struct{} { + if interval <= 0 { + interval = time.Second + } + ticker := time.NewTicker(interval) + stopChan := make(chan struct{}) + fn() + go func() { + for { + select { + case <-ticker.C: + fn() + case <-stopChan: + ticker.Stop() + return + } + } + }() + + return stopChan +}