теперь сервер раз в 30 секунд обновляет последний прослушанный трек, добавил поле под него в app

design
serr 2025-05-19 17:03:18 +03:00
parent 9aa39d8f65
commit 8c5c5d6150
7 changed files with 98 additions and 51 deletions

16
main.go
View File

@ -8,6 +8,7 @@ import (
"main/mvc/models" "main/mvc/models"
"main/tools" "main/tools"
"net/http" "net/http"
"time"
) )
func main() { func main() {
@ -25,6 +26,19 @@ func main() {
// Настройка маршрутов // Настройка маршрутов
router := setupRoutes(app) 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 { if ok, err := tools.IsIPInUse(app.Cfg.ServerIP); err != nil {
log.Fatal(err) log.Fatal(err)
@ -61,7 +75,7 @@ func setupRoutes(app *models.App) *http.ServeMux {
// Api // Api
{ {
router.Handle("/api/lastfm", m(controllers.LastfmHandler(app))) router.Handle("/api/lastfm", m(controllers.LastFMHandler(app)))
} }
return router return router

View File

@ -2,35 +2,19 @@ package controllers
import ( import (
"fmt" "fmt"
"log"
"main/mvc/models" "main/mvc/models"
"net/http" "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) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var err error sendLastFM(w, app.LastfmLastTrack)
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)
}) })
} }
// Отправляет страницу // Отправляет страницу
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.Header().Set("Content-Type", "text/html; charset=utf-8")
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
fmt.Fprint(w, data) fmt.Fprint(w, data)

View File

@ -7,11 +7,12 @@ import (
) )
type App struct { type App struct {
Cfg *Config // Сонфиг Cfg *Config // Сонфиг
Posts models_pages.Posts // Посты Posts models_pages.Posts // Посты
Templates *template.Template // Шаблоны страниц Templates *template.Template // Шаблоны страниц
PagesCache *Cache // Кэш (отрендеренные странички) PagesCache *Cache // Кэш (отрендеренные странички)
Version int64 // Время запуска LastfmLastTrack string // Последний трек, полученный с ластфм
Version int64 // Время запуска
} }
// Инициализирует приложение // Инициализирует приложение
@ -36,5 +37,7 @@ func InitApp() (*App, error) {
} }
// Инициализация кэша // Инициализация кэша
app.PagesCache = initCache() app.PagesCache = initCache()
// Строка по умолчанию для последнего прослушанного трека
app.LastfmLastTrack = "None"
return app, nil return app, nil
} }

View File

@ -3,6 +3,7 @@ package models
import ( import (
"encoding/json" "encoding/json"
"os" "os"
"time"
) )
const ( const (
@ -10,18 +11,19 @@ const (
) )
type Config struct { type Config struct {
PostsDir string PostsDir string
AssetsDir string AssetsDir string
TemplatesDir string TemplatesDir string
TemplatesExt string TemplatesExt string
LocalIP string LocalIP string
LocalPort string LocalPort string
ServerIP string ServerIP string
ServerPort string ServerPort string
ServerDomain string ServerDomain string
Port string Port string
LastfmUsername string LastFMUsername string
LastfmToken string LastFMToken string
LastFMUpdateInterval time.Duration
} }
func loadConfig(configPath string) (*Config, error) { func loadConfig(configPath string) (*Config, error) {

View File

@ -7,24 +7,26 @@ import (
"net/http" "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 { type LastFMResponse struct {
RecentTracks struct { RecentTracks struct {
Track []struct { Tracks []LastFMTrack `json:"track"`
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"`
} `json:"recenttracks"` } `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) 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) resp, err := http.Get(url)
if err != nil { if err != nil {
@ -42,3 +44,18 @@ func GetRecentTracks(username, apiKey string) (*LastFMResponse, error) {
return &lastFMResponse, nil 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
}

View File

@ -43,7 +43,7 @@
updateLastfm(); updateLastfm();
setInterval(updateLastfm, 20000); setInterval(updateLastfm, 30000);
</script> </script>
</header> </header>
{{ end }} {{ end }}

27
tools/ticker.go Normal file
View File

@ -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
}