теперь сервер раз в 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/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

View File

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

View File

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

View File

@ -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) {

View File

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

View File

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