Implemented lastPlayedSong() function that retrieves one song from a playlist.log file that doesn't run external commands for it.
And now we start with an empty list.
This commit is contained in:
parent
23f246857e
commit
c935db8ce7
@ -1,11 +1,12 @@
|
|||||||
package radio
|
package radio
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"dwelling-radio/pkg/watcher"
|
"dwelling-radio/pkg/watcher"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os/exec"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
@ -17,6 +18,8 @@ import (
|
|||||||
const (
|
const (
|
||||||
IcecastPlaylistDateFormat = "02/Jan/2006:15:04:05 -0700"
|
IcecastPlaylistDateFormat = "02/Jan/2006:15:04:05 -0700"
|
||||||
SongTimeFormat = "2006 15:04-0700"
|
SongTimeFormat = "2006 15:04-0700"
|
||||||
|
|
||||||
|
bufferSize = 8192
|
||||||
)
|
)
|
||||||
|
|
||||||
type IcecastStatusDTO struct {
|
type IcecastStatusDTO struct {
|
||||||
@ -85,7 +88,7 @@ func IcecastLastPlayedSongs(lastNSongs int, playlistPath string) ([]Song, error)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return lastPlayedSongs(lastNSongs, playlistPath)
|
return make([]Song, 0), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func IcecastLastSong(playlistPath string) (Song, error) {
|
func IcecastLastSong(playlistPath string) (Song, error) {
|
||||||
@ -97,45 +100,65 @@ func IcecastLastSong(playlistPath string) (Song, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
songs, err := lastPlayedSongs(1, playlistPath)
|
song, err := lastPlayedSong(playlistPath)
|
||||||
if len(songs) == 0 {
|
if err != nil {
|
||||||
return Song{}, nil
|
return Song{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return songs[0], err
|
return *song, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func lastPlayedSongs(lastNSongs int, playlistPath string) ([]Song, error) {
|
func lastPlayedSong(playlistPath string) (*Song, error) {
|
||||||
songs := make([]Song, 0)
|
buf := make([]byte, bufferSize)
|
||||||
|
var last_song_line string
|
||||||
|
|
||||||
cmd := fmt.Sprintf("tail -n%d %s | head -n-1 | cut -d'|' -f1,3,4", lastNSongs+1, playlistPath)
|
playlist, err := os.Open(playlistPath)
|
||||||
out, err := exec.Command("bash", "-c", cmd).CombinedOutput()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return songs, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(out) == 0 {
|
playlist_stat, _ := playlist.Stat()
|
||||||
return songs, nil
|
|
||||||
|
if playlist_stat.Size() == 0 {
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, song := range strings.Split(string(out), "\n") {
|
playlist.Seek(-bufferSize, os.SEEK_END)
|
||||||
ts := strings.Split(song, "|")
|
|
||||||
if len(ts) <= 1 {
|
_, err = playlist.Read(buf)
|
||||||
continue
|
if err != nil && err != io.EOF {
|
||||||
}
|
return nil, err
|
||||||
tim, _ := time.Parse(IcecastPlaylistDateFormat, ts[0])
|
|
||||||
songs = append(songs, Song{
|
|
||||||
Time: tim.Format(SongTimeFormat),
|
|
||||||
Listeners: ts[1],
|
|
||||||
Song: ts[2]})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return songs, nil
|
newline_end_pos := bytes.LastIndexByte(buf, '\n')
|
||||||
|
|
||||||
|
if newline_end_pos == -1 && !bytes.ContainsRune(buf, '|') {
|
||||||
|
return nil, nil
|
||||||
|
} else if newline_end_pos == -1 {
|
||||||
|
newline_end_pos = len(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
newline_start_pos := bytes.LastIndexByte(buf[:newline_end_pos-1], '\n')
|
||||||
|
|
||||||
|
last_song_line = string(buf[newline_start_pos+1 : newline_end_pos-1])
|
||||||
|
|
||||||
|
if strings.Count(last_song_line, "|") != 3 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
fields := strings.Split(last_song_line, "|")
|
||||||
|
|
||||||
|
tim, _ := time.Parse(IcecastPlaylistDateFormat, fields[0])
|
||||||
|
|
||||||
|
return &Song{
|
||||||
|
Time: tim.Format(SongTimeFormat),
|
||||||
|
Listeners: fields[2],
|
||||||
|
Song: fields[3]}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var playlistWatcher watcher.InotifyWatcher
|
var playlistWatcher watcher.InotifyWatcher
|
||||||
var playlistFired chan uint32 = make(chan uint32)
|
var playlistFired chan uint32 = make(chan uint32)
|
||||||
var lastPlayedCache []Song
|
var lastPlayedCache []Song = make([]Song, 10)
|
||||||
var lastPlayedCacheMutex sync.Mutex
|
var lastPlayedCacheMutex sync.Mutex
|
||||||
|
|
||||||
func IcecastWatchPlaylist(playlistPath string, lastNSongs int) error {
|
func IcecastWatchPlaylist(playlistPath string, lastNSongs int) error {
|
||||||
@ -157,9 +180,11 @@ func IcecastWatchPlaylist(playlistPath string, lastNSongs int) error {
|
|||||||
case mask := <-playlistFired:
|
case mask := <-playlistFired:
|
||||||
if mask&syscall.IN_MODIFY > 0 {
|
if mask&syscall.IN_MODIFY > 0 {
|
||||||
lastPlayedCacheMutex.Lock()
|
lastPlayedCacheMutex.Lock()
|
||||||
songs, err := lastPlayedSongs(lastNSongs, playlistPath)
|
if song, err := lastPlayedSong(playlistPath); err == nil {
|
||||||
if err == nil && len(songs) > 0 {
|
lastPlayedCache = append(lastPlayedCache, *song)
|
||||||
lastPlayedCache = songs
|
if len(lastPlayedCache) > lastNSongs {
|
||||||
|
lastPlayedCache = lastPlayedCache[1:]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
lastPlayedCacheMutex.Unlock()
|
lastPlayedCacheMutex.Unlock()
|
||||||
} else if mask&syscall.IN_IGNORED > 0 {
|
} else if mask&syscall.IN_IGNORED > 0 {
|
||||||
@ -171,13 +196,6 @@ func IcecastWatchPlaylist(playlistPath string, lastNSongs int) error {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
lastPlayedCacheMutex.Lock()
|
|
||||||
songs, err := lastPlayedSongs(lastNSongs, playlistPath)
|
|
||||||
if err == nil && len(songs) > 0 {
|
|
||||||
lastPlayedCache = songs
|
|
||||||
}
|
|
||||||
lastPlayedCacheMutex.Unlock()
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user