icecastLastPlayedSongs was replaced by icecastCurrentSong that fetch only one song at the very end of a playlist.log. Also added a benchmark for this func.
This commit is contained in:
parent
7bb91cfcbe
commit
60045d4ca2
@ -19,7 +19,9 @@ const (
|
||||
IcecastPlaylistDateFormat = "02/Jan/2006:15:04:05 -0700"
|
||||
SongTimeFormat = "2006 15:04-0700"
|
||||
|
||||
bufferSizePerLine = 320
|
||||
bufferSizePerLine = 512
|
||||
separatorOne = 26
|
||||
separatorTwo = 38 + 1
|
||||
)
|
||||
|
||||
var (
|
||||
@ -96,61 +98,46 @@ func IcecastLastSong(playlistPath string) *Song {
|
||||
return nil
|
||||
}
|
||||
|
||||
func icecastLastPlayedSongs(playlistPath string, n int) ([]Song, error) {
|
||||
var buf []byte
|
||||
var offset int64 = 0
|
||||
var bufferSize int64 = int64(n) * bufferSizePerLine
|
||||
|
||||
playlist, err := os.Open(playlistPath)
|
||||
func icecastCurrentSong(playlistPath string) (*Song, error) {
|
||||
fd, err := os.Open(playlistPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer playlist.Close()
|
||||
defer fd.Close()
|
||||
|
||||
playlist_stat, _ := playlist.Stat()
|
||||
|
||||
if playlist_stat.Size() == 0 {
|
||||
fdSize, _ := fd.Seek(0, io.SeekEnd)
|
||||
if fdSize == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if playlist_stat.Size() < bufferSize {
|
||||
buf = make([]byte, playlist_stat.Size())
|
||||
} else {
|
||||
buf = make([]byte, bufferSize)
|
||||
offset = playlist_stat.Size() - bufferSize
|
||||
var bufSize int64 = bufferSizePerLine
|
||||
if fdSize < bufferSizePerLine {
|
||||
bufSize = fdSize
|
||||
}
|
||||
|
||||
_, err = playlist.ReadAt(buf, offset)
|
||||
if err != nil && err != io.EOF {
|
||||
_, err = fd.Seek(-bufSize, io.SeekEnd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
lines := bytes.Split(buf, []byte("\n"))
|
||||
buf := make([]byte, bufSize)
|
||||
|
||||
if len(lines) < 2 {
|
||||
return nil, nil
|
||||
_, err = fd.Read(buf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
lines = lines[:len(lines)-1]
|
||||
curSongEnd := bytes.LastIndexByte(buf, '\n')
|
||||
line := buf[bytes.LastIndexByte(buf[:curSongEnd], '\n')+1 : curSongEnd]
|
||||
|
||||
if len(lines) > n {
|
||||
lines = lines[len(lines)-n:]
|
||||
}
|
||||
songTime, _ := time.Parse(IcecastPlaylistDateFormat, string(line[:separatorOne]))
|
||||
|
||||
songs := make([]Song, 0, len(lines))
|
||||
separatorThree := bytes.LastIndexByte(line, '|')
|
||||
|
||||
for _, line := range lines {
|
||||
fields := bytes.Split(line, []byte("|"))
|
||||
|
||||
tim, _ := time.Parse(IcecastPlaylistDateFormat, string(fields[0]))
|
||||
|
||||
songs = append(songs, Song{
|
||||
Time: tim.Format(SongTimeFormat),
|
||||
Listeners: string(fields[2]),
|
||||
Song: string(fields[3])})
|
||||
}
|
||||
|
||||
return songs, nil
|
||||
return &Song{
|
||||
Time: songTime.Format(SongTimeFormat),
|
||||
Listeners: string(line[separatorTwo:separatorThree]),
|
||||
Song: string(line[separatorThree+1:])}, nil
|
||||
}
|
||||
|
||||
type PlaylistLogWatcher struct {
|
||||
@ -180,13 +167,14 @@ func (pw *PlaylistLogWatcher) Watch(playlistPath string, n int) (err error) {
|
||||
pw.watcher.WatchForMask(pw.changed, watcher.ModIgnMask)
|
||||
|
||||
if lastPlayedCache == nil {
|
||||
lastPlayedCache = make([]Song, n)
|
||||
songs, err := icecastLastPlayedSongs(playlistPath, n)
|
||||
if err == nil && len(songs) > 0 {
|
||||
copy(lastPlayedCache, songs)
|
||||
} else if err != nil {
|
||||
log.Fatalln("failed to retrieve last songs:", err)
|
||||
lastPlayedCache = make([]Song, 0, n)
|
||||
}
|
||||
|
||||
cur, err := icecastCurrentSong(playlistPath)
|
||||
if err != nil {
|
||||
log.Println("failed to fetch current song:", err)
|
||||
} else if cur != nil && currentlyPlaying.Time != "" {
|
||||
currentlyPlaying = *cur
|
||||
}
|
||||
|
||||
go func() {
|
||||
@ -195,19 +183,19 @@ func (pw *PlaylistLogWatcher) Watch(playlistPath string, n int) (err error) {
|
||||
|
||||
if mask&syscall.IN_MODIFY > 0 {
|
||||
lastPlayedCacheMutex.Lock()
|
||||
songs, err := icecastLastPlayedSongs(playlistPath, 1)
|
||||
if err == nil && len(songs) > 0 {
|
||||
song, err := icecastCurrentSong(playlistPath)
|
||||
if err == nil && song != nil {
|
||||
CheckAndUpdateMostListenedSong(song, ¤tlyPlaying)
|
||||
if currentlyPlaying.Time == "" {
|
||||
currentlyPlaying = songs[0]
|
||||
currentlyPlaying = *song
|
||||
} else {
|
||||
currentlyPlaying.Listeners = songs[0].Listeners
|
||||
currentlyPlaying.Listeners = song.Listeners
|
||||
if len(lastPlayedCache) == n {
|
||||
lastPlayedCache = append(lastPlayedCache[1:], currentlyPlaying)
|
||||
} else {
|
||||
lastPlayedCache = append(lastPlayedCache, currentlyPlaying)
|
||||
}
|
||||
currentlyPlaying = songs[0]
|
||||
currentlyPlaying = *song
|
||||
}
|
||||
} else if err != nil {
|
||||
log.Println("failed to retrieve last songs:", err)
|
||||
|
12
internal/radio/icecast_test.go
Normal file
12
internal/radio/icecast_test.go
Normal file
@ -0,0 +1,12 @@
|
||||
package radio
|
||||
|
||||
import "testing"
|
||||
|
||||
const playlistPath = "../../p.log"
|
||||
|
||||
func BenchmarkIcecastCurrentSong(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
s, err := icecastCurrentSong(playlistPath)
|
||||
b.Log(s, err)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user